summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--dex2oat/dex2oat.cc4
-rw-r--r--dex2oat/dex2oat_test.cc2
-rw-r--r--dex2oat/linker/oat_writer.cc57
-rw-r--r--dex2oat/linker/oat_writer_test.cc5
-rw-r--r--oatdump/oatdump.cc8
-rw-r--r--patchoat/patchoat.cc56
-rw-r--r--runtime/gc/heap.cc16
-rw-r--r--runtime/gc/heap.h1
-rw-r--r--runtime/gc/heap_test.cc21
-rw-r--r--runtime/oat_file_assistant.cc2
-rw-r--r--runtime/vdex_file.cc59
-rw-r--r--runtime/vdex_file.h168
12 files changed, 274 insertions, 125 deletions
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index 73afbad184..9b6771d3b5 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -1398,8 +1398,8 @@ class Dex2Oat FINAL {
std::unique_ptr<linker::BufferedOutputStream> vdex_out =
std::make_unique<linker::BufferedOutputStream>(
std::make_unique<linker::FileOutputStream>(vdex_files_.back().get()));
- if (!vdex_out->WriteFully(&VdexFile::Header::kVdexInvalidMagic,
- arraysize(VdexFile::Header::kVdexInvalidMagic))) {
+ if (!vdex_out->WriteFully(&VdexFile::VerifierDepsHeader::kVdexInvalidMagic,
+ arraysize(VdexFile::VerifierDepsHeader::kVdexInvalidMagic))) {
PLOG(ERROR) << "Failed to invalidate vdex header. File: " << vdex_out->GetLocation();
return false;
}
diff --git a/dex2oat/dex2oat_test.cc b/dex2oat/dex2oat_test.cc
index 96dd319946..094dfee3a6 100644
--- a/dex2oat/dex2oat_test.cc
+++ b/dex2oat/dex2oat_test.cc
@@ -1834,7 +1834,7 @@ TEST_F(Dex2oatTest, DontExtract) {
/*unquicken*/ false,
&error_msg));
ASSERT_TRUE(vdex != nullptr);
- EXPECT_EQ(vdex->GetHeader().GetDexSize(), 0u) << output_;
+ EXPECT_FALSE(vdex->HasDexSection()) << output_;
}
std::unique_ptr<OatFile> odex_file(OatFile::Open(odex_location.c_str(),
odex_location.c_str(),
diff --git a/dex2oat/linker/oat_writer.cc b/dex2oat/linker/oat_writer.cc
index c72beea6ce..089aa80ad4 100644
--- a/dex2oat/linker/oat_writer.cc
+++ b/dex2oat/linker/oat_writer.cc
@@ -555,8 +555,9 @@ bool OatWriter::AddVdexDexFilesSource(const VdexFile& vdex_file,
const char* location,
CreateTypeLookupTable create_type_lookup_table) {
DCHECK(write_state_ == WriteState::kAddingDexFileSources);
+ DCHECK(vdex_file.HasDexSection());
const uint8_t* current_dex_data = nullptr;
- for (size_t i = 0; i < vdex_file.GetHeader().GetNumberOfDexFiles(); ++i) {
+ for (size_t i = 0; i < vdex_file.GetVerifierDepsHeader().GetNumberOfDexFiles(); ++i) {
current_dex_data = vdex_file.GetNextDexFileData(current_dex_data);
if (current_dex_data == nullptr) {
LOG(ERROR) << "Unexpected number of dex files in vdex " << location;
@@ -659,7 +660,8 @@ bool OatWriter::WriteAndOpenDexFiles(
// Initialize VDEX and OAT headers.
// Reserve space for Vdex header and checksums.
- vdex_size_ = sizeof(VdexFile::Header) + oat_dex_files_.size() * sizeof(VdexFile::VdexChecksum);
+ vdex_size_ = sizeof(VdexFile::VerifierDepsHeader) +
+ oat_dex_files_.size() * sizeof(VdexFile::VdexChecksum);
oat_size_ = InitOatHeader(instruction_set,
instruction_set_features,
dchecked_integral_cast<uint32_t>(oat_dex_files_.size()),
@@ -3333,8 +3335,6 @@ bool OatWriter::WriteDexFiles(OutputStream* out,
CopyOption copy_dex_files) {
TimingLogger::ScopedTiming split("Write Dex files", timings_);
- vdex_dex_files_offset_ = vdex_size_;
-
// If extraction is enabled, only do it if not all the dex files are aligned and uncompressed.
if (copy_dex_files == CopyOption::kOnlyIfCompressed) {
extract_dex_files_into_vdex_ = false;
@@ -3357,6 +3357,9 @@ bool OatWriter::WriteDexFiles(OutputStream* out,
}
if (extract_dex_files_into_vdex_) {
+ // Add the dex section header.
+ vdex_size_ += sizeof(VdexFile::DexSectionHeader);
+ vdex_dex_files_offset_ = vdex_size_;
// Write dex files.
for (OatDexFile& oat_dex_file : oat_dex_files_) {
if (!WriteDexFile(out, file, &oat_dex_file, update_input_vdex)) {
@@ -4076,8 +4079,9 @@ bool OatWriter::WriteDexLayoutSections(
bool OatWriter::WriteChecksumsAndVdexHeader(OutputStream* vdex_out) {
// Write checksums
- off_t actual_offset = vdex_out->Seek(sizeof(VdexFile::Header), kSeekSet);
- if (actual_offset != sizeof(VdexFile::Header)) {
+ off_t checksums_offset = sizeof(VdexFile::VerifierDepsHeader);
+ off_t actual_offset = vdex_out->Seek(checksums_offset, kSeekSet);
+ if (actual_offset != checksums_offset) {
PLOG(ERROR) << "Failed to seek to the checksum location of vdex file. Actual: " << actual_offset
<< " File: " << vdex_out->GetLocation();
return false;
@@ -4094,6 +4098,27 @@ bool OatWriter::WriteChecksumsAndVdexHeader(OutputStream* vdex_out) {
size_vdex_checksums_ += sizeof(VdexFile::VdexChecksum);
}
+ // Maybe write dex section header.
+ DCHECK_NE(vdex_verifier_deps_offset_, 0u);
+ DCHECK_NE(vdex_quickening_info_offset_, 0u);
+
+ bool has_dex_section = extract_dex_files_into_vdex_;
+ if (has_dex_section) {
+ DCHECK_NE(vdex_dex_files_offset_, 0u);
+ size_t dex_section_size = vdex_dex_shared_data_offset_ - vdex_dex_files_offset_;
+ size_t dex_shared_data_size = vdex_verifier_deps_offset_ - vdex_dex_shared_data_offset_;
+ size_t quickening_info_section_size = vdex_size_ - vdex_quickening_info_offset_;
+
+ VdexFile::DexSectionHeader dex_section_header(dex_section_size,
+ dex_shared_data_size,
+ quickening_info_section_size);
+ if (!vdex_out->WriteFully(&dex_section_header, sizeof(VdexFile::DexSectionHeader))) {
+ PLOG(ERROR) << "Failed to write vdex header. File: " << vdex_out->GetLocation();
+ return false;
+ }
+ size_vdex_header_ += sizeof(VdexFile::DexSectionHeader);
+ }
+
// Write header.
actual_offset = vdex_out->Seek(0, kSeekSet);
if (actual_offset != 0) {
@@ -4102,25 +4127,15 @@ bool OatWriter::WriteChecksumsAndVdexHeader(OutputStream* vdex_out) {
return false;
}
- DCHECK_NE(vdex_dex_files_offset_, 0u);
- DCHECK_NE(vdex_verifier_deps_offset_, 0u);
- DCHECK_NE(vdex_quickening_info_offset_, 0u);
-
- size_t dex_section_size = vdex_dex_shared_data_offset_ - vdex_dex_files_offset_;
- size_t dex_shared_data_size = vdex_verifier_deps_offset_ - vdex_dex_shared_data_offset_;
size_t verifier_deps_section_size = vdex_quickening_info_offset_ - vdex_verifier_deps_offset_;
- size_t quickening_info_section_size = vdex_size_ - vdex_quickening_info_offset_;
-
- VdexFile::Header vdex_header(oat_dex_files_.size(),
- dex_section_size,
- dex_shared_data_size,
- verifier_deps_section_size,
- quickening_info_section_size);
- if (!vdex_out->WriteFully(&vdex_header, sizeof(VdexFile::Header))) {
+
+ VdexFile::VerifierDepsHeader deps_header(
+ oat_dex_files_.size(), verifier_deps_section_size, has_dex_section);
+ if (!vdex_out->WriteFully(&deps_header, sizeof(VdexFile::VerifierDepsHeader))) {
PLOG(ERROR) << "Failed to write vdex header. File: " << vdex_out->GetLocation();
return false;
}
- size_vdex_header_ = sizeof(VdexFile::Header);
+ size_vdex_header_ += sizeof(VdexFile::VerifierDepsHeader);
if (!vdex_out->Flush()) {
PLOG(ERROR) << "Failed to flush stream after writing to vdex file."
diff --git a/dex2oat/linker/oat_writer_test.cc b/dex2oat/linker/oat_writer_test.cc
index 00b9abe69b..0148a5792c 100644
--- a/dex2oat/linker/oat_writer_test.cc
+++ b/dex2oat/linker/oat_writer_test.cc
@@ -663,7 +663,8 @@ void OatTest::TestDexFileInput(bool verify, bool low_4gb, bool use_profile) {
dex_file2_data->GetHeader().file_size_));
ASSERT_EQ(dex_file2_data->GetLocation(), opened_dex_file2->GetLocation());
- const VdexFile::Header &vdex_header = opened_oat_file->GetVdexFile()->GetHeader();
+ const VdexFile::DexSectionHeader &vdex_header =
+ opened_oat_file->GetVdexFile()->GetDexSectionHeader();
if (!compiler_driver_->GetCompilerOptions().IsQuickeningCompilationEnabled()) {
// If quickening is enabled we will always write the table since there is no special logic that
// checks for all methods not being quickened (not worth the complexity).
@@ -672,7 +673,7 @@ void OatTest::TestDexFileInput(bool verify, bool low_4gb, bool use_profile) {
int64_t actual_vdex_size = vdex_file.GetFile()->GetLength();
ASSERT_GE(actual_vdex_size, 0);
- ASSERT_EQ((uint64_t) actual_vdex_size, vdex_header.GetComputedFileSize());
+ ASSERT_EQ((uint64_t) actual_vdex_size, opened_oat_file->GetVdexFile()->GetComputedFileSize());
}
TEST_F(OatTest, DexFileInputCheckOutput) {
diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc
index 8069408b5a..9a49fb4752 100644
--- a/oatdump/oatdump.cc
+++ b/oatdump/oatdump.cc
@@ -567,7 +567,7 @@ class OatDumper {
if (!options_.dump_header_only_) {
VariableIndentationOutputStream vios(&os);
- VdexFile::Header vdex_header = oat_file_.GetVdexFile()->GetHeader();
+ VdexFile::VerifierDepsHeader vdex_header = oat_file_.GetVdexFile()->GetVerifierDepsHeader();
if (vdex_header.IsValid()) {
std::string error_msg;
std::vector<const DexFile*> dex_files;
@@ -584,8 +584,10 @@ class OatDumper {
} else {
os << "UNRECOGNIZED vdex file, magic "
<< vdex_header.GetMagic()
- << ", version "
- << vdex_header.GetVersion()
+ << ", verifier deps version "
+ << vdex_header.GetVerifierDepsVersion()
+ << ", dex section version "
+ << vdex_header.GetDexSectionVersion()
<< "\n";
}
for (size_t i = 0; i < oat_dex_files_.size(); i++) {
diff --git a/patchoat/patchoat.cc b/patchoat/patchoat.cc
index 3df640902a..b9a9a69ab5 100644
--- a/patchoat/patchoat.cc
+++ b/patchoat/patchoat.cc
@@ -65,6 +65,8 @@ namespace art {
using android::base::StringPrintf;
+namespace {
+
static const OatHeader* GetOatHeader(const ElfFile* elf_file) {
uint64_t off = 0;
if (!elf_file->GetSectionOffsetAndSize(".rodata", &off, nullptr)) {
@@ -127,6 +129,38 @@ static bool SymlinkFile(const std::string& input_filename, const std::string& ou
return true;
}
+// Holder class for runtime options and related objects.
+class PatchoatRuntimeOptionsHolder {
+ public:
+ PatchoatRuntimeOptionsHolder(const std::string& image_location, InstructionSet isa) {
+ options_.push_back(std::make_pair("compilercallbacks", &callbacks_));
+ img_ = "-Ximage:" + image_location;
+ options_.push_back(std::make_pair(img_.c_str(), nullptr));
+ isa_name_ = GetInstructionSetString(isa);
+ options_.push_back(std::make_pair("imageinstructionset",
+ reinterpret_cast<const void*>(isa_name_.c_str())));
+ options_.push_back(std::make_pair("-Xno-sig-chain", nullptr));
+ // We do not want the runtime to attempt to patch the image.
+ options_.push_back(std::make_pair("-Xnorelocate", nullptr));
+ // Don't try to compile.
+ options_.push_back(std::make_pair("-Xnoimage-dex2oat", nullptr));
+ // Do not accept broken image.
+ options_.push_back(std::make_pair("-Xno-dex-file-fallback", nullptr));
+ }
+
+ const RuntimeOptions& GetRuntimeOptions() {
+ return options_;
+ }
+
+ private:
+ RuntimeOptions options_;
+ NoopCompilerCallbacks callbacks_;
+ std::string isa_name_;
+ std::string img_;
+};
+
+} // namespace
+
bool PatchOat::GeneratePatch(
const MemMap& original,
const MemMap& relocated,
@@ -440,17 +474,10 @@ bool PatchOat::Patch(const std::string& image_location,
TimingLogger::ScopedTiming t("Runtime Setup", timings);
CHECK_NE(isa, InstructionSet::kNone);
- const char* isa_name = GetInstructionSetString(isa);
// Set up the runtime
- RuntimeOptions options;
- NoopCompilerCallbacks callbacks;
- options.push_back(std::make_pair("compilercallbacks", &callbacks));
- std::string img = "-Ximage:" + image_location;
- options.push_back(std::make_pair(img.c_str(), nullptr));
- options.push_back(std::make_pair("imageinstructionset", reinterpret_cast<const void*>(isa_name)));
- options.push_back(std::make_pair("-Xno-sig-chain", nullptr));
- if (!Runtime::Create(options, false)) {
+ PatchoatRuntimeOptionsHolder options_holder(image_location, isa);
+ if (!Runtime::Create(options_holder.GetRuntimeOptions(), false)) {
LOG(ERROR) << "Unable to initialize runtime";
return false;
}
@@ -608,17 +635,10 @@ bool PatchOat::Verify(const std::string& image_location,
TimingLogger::ScopedTiming t("Runtime Setup", timings);
CHECK_NE(isa, InstructionSet::kNone);
- const char* isa_name = GetInstructionSetString(isa);
// Set up the runtime
- RuntimeOptions options;
- NoopCompilerCallbacks callbacks;
- options.push_back(std::make_pair("compilercallbacks", &callbacks));
- std::string img = "-Ximage:" + image_location;
- options.push_back(std::make_pair(img.c_str(), nullptr));
- options.push_back(std::make_pair("imageinstructionset", reinterpret_cast<const void*>(isa_name)));
- options.push_back(std::make_pair("-Xno-sig-chain", nullptr));
- if (!Runtime::Create(options, false)) {
+ PatchoatRuntimeOptionsHolder options_holder(image_location, isa);
+ if (!Runtime::Create(options_holder.GetRuntimeOptions(), false)) {
LOG(ERROR) << "Unable to initialize runtime";
return false;
}
diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc
index 3dc2cb572e..3011c37f3a 100644
--- a/runtime/gc/heap.cc
+++ b/runtime/gc/heap.cc
@@ -145,15 +145,15 @@ static constexpr bool kUsePartialTlabs = true;
#if defined(__LP64__) || !defined(ADDRESS_SANITIZER)
// 300 MB (0x12c00000) - (default non-moving space capacity).
-static uint8_t* const kPreferredAllocSpaceBegin =
- reinterpret_cast<uint8_t*>(300 * MB - Heap::kDefaultNonMovingSpaceCapacity);
+uint8_t* const Heap::kPreferredAllocSpaceBegin =
+ reinterpret_cast<uint8_t*>(300 * MB - kDefaultNonMovingSpaceCapacity);
#else
#ifdef __ANDROID__
// For 32-bit Android, use 0x20000000 because asan reserves 0x04000000 - 0x20000000.
-static uint8_t* const kPreferredAllocSpaceBegin = reinterpret_cast<uint8_t*>(0x20000000);
+uint8_t* const Heap::kPreferredAllocSpaceBegin = reinterpret_cast<uint8_t*>(0x20000000);
#else
// For 32-bit host, use 0x40000000 because asan uses most of the space below this.
-static uint8_t* const kPreferredAllocSpaceBegin = reinterpret_cast<uint8_t*>(0x40000000);
+uint8_t* const Heap::kPreferredAllocSpaceBegin = reinterpret_cast<uint8_t*>(0x40000000);
#endif
#endif
@@ -382,10 +382,10 @@ Heap::Heap(size_t initial_size,
const char* space_name = is_zygote ? kZygoteSpaceName : kNonMovingSpaceName;
// Reserve the non moving mem map before the other two since it needs to be at a specific
// address.
- non_moving_space_mem_map.reset(
- MemMap::MapAnonymous(space_name, requested_alloc_space_begin,
- non_moving_space_capacity, PROT_READ | PROT_WRITE, true, false,
- &error_str));
+ non_moving_space_mem_map.reset(MapAnonymousPreferredAddress(space_name,
+ requested_alloc_space_begin,
+ non_moving_space_capacity,
+ &error_str));
CHECK(non_moving_space_mem_map != nullptr) << error_str;
// Try to reserve virtual memory at a lower address if we have a separate non moving space.
request_begin = kPreferredAllocSpaceBegin + non_moving_space_capacity;
diff --git a/runtime/gc/heap.h b/runtime/gc/heap.h
index 4de03318a0..5ce01bc9d2 100644
--- a/runtime/gc/heap.h
+++ b/runtime/gc/heap.h
@@ -144,6 +144,7 @@ class Heap {
static constexpr size_t kDefaultLargeObjectThreshold = kMinLargeObjectThreshold;
// Whether or not parallel GC is enabled. If not, then we never create the thread pool.
static constexpr bool kDefaultEnableParallelGC = false;
+ static uint8_t* const kPreferredAllocSpaceBegin;
// Whether or not we use the free list large object space. Only use it if USE_ART_LOW_4G_ALLOCATOR
// since this means that we have to use the slow msync loop in MemMap::MapAnonymous.
diff --git a/runtime/gc/heap_test.cc b/runtime/gc/heap_test.cc
index 2def52450b..c6b2120f5b 100644
--- a/runtime/gc/heap_test.cc
+++ b/runtime/gc/heap_test.cc
@@ -27,7 +27,26 @@
namespace art {
namespace gc {
-class HeapTest : public CommonRuntimeTest {};
+class HeapTest : public CommonRuntimeTest {
+ public:
+ void SetUp() OVERRIDE {
+ MemMap::Init();
+ std::string error_msg;
+ // Reserve the preferred address to force the heap to use another one for testing.
+ reserved_.reset(MemMap::MapAnonymous("ReserveMap",
+ gc::Heap::kPreferredAllocSpaceBegin,
+ 16 * KB,
+ PROT_READ,
+ /*low_4gb*/ true,
+ /*reuse*/ false,
+ &error_msg));
+ ASSERT_TRUE(reserved_ != nullptr) << error_msg;
+ CommonRuntimeTest::SetUp();
+ }
+
+ private:
+ std::unique_ptr<MemMap> reserved_;
+};
TEST_F(HeapTest, ClearGrowthLimit) {
Heap* heap = Runtime::Current()->GetHeap();
diff --git a/runtime/oat_file_assistant.cc b/runtime/oat_file_assistant.cc
index 5888c37582..38ca4c9623 100644
--- a/runtime/oat_file_assistant.cc
+++ b/runtime/oat_file_assistant.cc
@@ -408,7 +408,7 @@ bool OatFileAssistant::DexChecksumUpToDate(const VdexFile& file, std::string* er
return true;
}
- uint32_t number_of_dex_files = file.GetHeader().GetNumberOfDexFiles();
+ uint32_t number_of_dex_files = file.GetVerifierDepsHeader().GetNumberOfDexFiles();
if (required_dex_checksums->size() != number_of_dex_files) {
*error_msg = StringPrintf("expected %zu dex files but found %u",
required_dex_checksums->size(),
diff --git a/runtime/vdex_file.cc b/runtime/vdex_file.cc
index ba640556df..ec4dc417d3 100644
--- a/runtime/vdex_file.cc
+++ b/runtime/vdex_file.cc
@@ -36,32 +36,52 @@
namespace art {
-constexpr uint8_t VdexFile::Header::kVdexInvalidMagic[4];
-constexpr uint8_t VdexFile::Header::kVdexMagic[4];
-constexpr uint8_t VdexFile::Header::kVdexVersion[4];
+constexpr uint8_t VdexFile::VerifierDepsHeader::kVdexInvalidMagic[4];
+constexpr uint8_t VdexFile::VerifierDepsHeader::kVdexMagic[4];
+constexpr uint8_t VdexFile::VerifierDepsHeader::kVerifierDepsVersion[4];
+constexpr uint8_t VdexFile::VerifierDepsHeader::kDexSectionVersion[4];
+constexpr uint8_t VdexFile::VerifierDepsHeader::kDexSectionVersionEmpty[4];
-bool VdexFile::Header::IsMagicValid() const {
+bool VdexFile::VerifierDepsHeader::IsMagicValid() const {
return (memcmp(magic_, kVdexMagic, sizeof(kVdexMagic)) == 0);
}
-bool VdexFile::Header::IsVersionValid() const {
- return (memcmp(version_, kVdexVersion, sizeof(kVdexVersion)) == 0);
+bool VdexFile::VerifierDepsHeader::IsVerifierDepsVersionValid() const {
+ return (memcmp(verifier_deps_version_, kVerifierDepsVersion, sizeof(kVerifierDepsVersion)) == 0);
}
-VdexFile::Header::Header(uint32_t number_of_dex_files,
- uint32_t dex_size,
- uint32_t dex_shared_data_size,
- uint32_t verifier_deps_size,
- uint32_t quickening_info_size)
+bool VdexFile::VerifierDepsHeader::IsDexSectionVersionValid() const {
+ return (memcmp(dex_section_version_, kDexSectionVersion, sizeof(kDexSectionVersion)) == 0) ||
+ (memcmp(dex_section_version_, kDexSectionVersionEmpty, sizeof(kDexSectionVersionEmpty)) == 0);
+}
+
+bool VdexFile::VerifierDepsHeader::HasDexSection() const {
+ return (memcmp(dex_section_version_, kDexSectionVersion, sizeof(kDexSectionVersion)) == 0);
+}
+
+VdexFile::VerifierDepsHeader::VerifierDepsHeader(uint32_t number_of_dex_files,
+ uint32_t verifier_deps_size,
+ bool has_dex_section)
: number_of_dex_files_(number_of_dex_files),
- dex_size_(dex_size),
- dex_shared_data_size_(dex_shared_data_size),
- verifier_deps_size_(verifier_deps_size),
- quickening_info_size_(quickening_info_size) {
+ verifier_deps_size_(verifier_deps_size) {
memcpy(magic_, kVdexMagic, sizeof(kVdexMagic));
- memcpy(version_, kVdexVersion, sizeof(kVdexVersion));
+ memcpy(verifier_deps_version_, kVerifierDepsVersion, sizeof(kVerifierDepsVersion));
+ if (has_dex_section) {
+ memcpy(dex_section_version_, kDexSectionVersion, sizeof(kDexSectionVersion));
+ } else {
+ memcpy(dex_section_version_, kDexSectionVersionEmpty, sizeof(kDexSectionVersionEmpty));
+ }
DCHECK(IsMagicValid());
- DCHECK(IsVersionValid());
+ DCHECK(IsVerifierDepsVersionValid());
+ DCHECK(IsDexSectionVersionValid());
+}
+
+VdexFile::DexSectionHeader::DexSectionHeader(uint32_t dex_size,
+ uint32_t dex_shared_data_size,
+ uint32_t quickening_info_size)
+ : dex_size_(dex_size),
+ dex_shared_data_size_(dex_shared_data_size),
+ quickening_info_size_(quickening_info_size) {
}
std::unique_ptr<VdexFile> VdexFile::OpenAtAddress(uint8_t* mmap_addr,
@@ -145,7 +165,7 @@ std::unique_ptr<VdexFile> VdexFile::OpenAtAddress(uint8_t* mmap_addr,
return nullptr;
}
- if (unquicken) {
+ if (unquicken && vdex->HasDexSection()) {
std::vector<std::unique_ptr<const DexFile>> unique_ptr_dex_files;
if (!vdex->OpenAllDexFiles(&unique_ptr_dex_files, error_msg)) {
return nullptr;
@@ -153,7 +173,8 @@ std::unique_ptr<VdexFile> VdexFile::OpenAtAddress(uint8_t* mmap_addr,
vdex->Unquicken(MakeNonOwningPointerVector(unique_ptr_dex_files),
/* decompile_return_instruction */ false);
// Update the quickening info size to pretend there isn't any.
- reinterpret_cast<Header*>(vdex->mmap_->Begin())->quickening_info_size_ = 0;
+ size_t offset = vdex->GetDexSectionHeaderOffset();
+ reinterpret_cast<DexSectionHeader*>(vdex->mmap_->Begin() + offset)->quickening_info_size_ = 0;
}
*error_msg = "Success";
diff --git a/runtime/vdex_file.h b/runtime/vdex_file.h
index 72f03f266a..77e1f2ccfe 100644
--- a/runtime/vdex_file.h
+++ b/runtime/vdex_file.h
@@ -35,51 +35,53 @@ class DexFile;
// memory and provides tools for accessing its individual sections.
//
// File format:
-// VdexFile::Header fixed-length header
+// VdexFile::VerifierDepsHeader fixed-length header
+// Dex file checksums
+//
+// Optionally:
+// VdexFile::DexSectionHeader fixed-length header
+//
+// quicken_table_off[0] offset into QuickeningInfo section for offset table for DEX[0].
+// DEX[0] array of the input DEX files, the bytecode may have been quickened.
+// quicken_table_off[1]
+// DEX[1]
+// ...
+// DEX[D]
//
-// quicken_table_off[0] offset into QuickeningInfo section for offset table for DEX[0].
-// DEX[0] array of the input DEX files, the bytecode may have been quickened.
-// quicken_table_off[1]
-// DEX[1]
-// ...
-// DEX[D]
// VerifierDeps
// uint8[D][] verification dependencies
-// QuickeningInfo
-// uint8[D][] quickening data
-// uint32[D][] quickening data offset tables
+//
+// Optionally:
+// QuickeningInfo
+// uint8[D][] quickening data
+// uint32[D][] quickening data offset tables
class VdexFile {
public:
- struct Header {
+ struct VerifierDepsHeader {
public:
- Header(uint32_t number_of_dex_files_,
- uint32_t dex_size,
- uint32_t dex_shared_data_size,
- uint32_t verifier_deps_size,
- uint32_t quickening_info_size);
+ VerifierDepsHeader(uint32_t number_of_dex_files_,
+ uint32_t verifier_deps_size,
+ bool has_dex_section);
const char* GetMagic() const { return reinterpret_cast<const char*>(magic_); }
- const char* GetVersion() const { return reinterpret_cast<const char*>(version_); }
+ const char* GetVerifierDepsVersion() const {
+ return reinterpret_cast<const char*>(verifier_deps_version_);
+ }
+ const char* GetDexSectionVersion() const {
+ return reinterpret_cast<const char*>(dex_section_version_);
+ }
bool IsMagicValid() const;
- bool IsVersionValid() const;
- bool IsValid() const { return IsMagicValid() && IsVersionValid(); }
+ bool IsVerifierDepsVersionValid() const;
+ bool IsDexSectionVersionValid() const;
+ bool IsValid() const {
+ return IsMagicValid() && IsVerifierDepsVersionValid() && IsDexSectionVersionValid();
+ }
+ bool HasDexSection() const;
- uint32_t GetDexSize() const { return dex_size_; }
- uint32_t GetDexSharedDataSize() const { return dex_shared_data_size_; }
uint32_t GetVerifierDepsSize() const { return verifier_deps_size_; }
- uint32_t GetQuickeningInfoSize() const { return quickening_info_size_; }
uint32_t GetNumberOfDexFiles() const { return number_of_dex_files_; }
- size_t GetComputedFileSize() const {
- return sizeof(Header) +
- GetSizeOfChecksumsSection() +
- GetDexSize() +
- GetDexSharedDataSize() +
- GetVerifierDepsSize() +
- GetQuickeningInfoSize();
- }
-
size_t GetSizeOfChecksumsSection() const {
return sizeof(VdexChecksum) * GetNumberOfDexFiles();
}
@@ -88,20 +90,62 @@ class VdexFile {
private:
static constexpr uint8_t kVdexMagic[] = { 'v', 'd', 'e', 'x' };
- // Last update: Change quickening info table format.
- static constexpr uint8_t kVdexVersion[] = { '0', '1', '8', '\0' };
+
+ // The format version of the verifier deps header and the verifier deps.
+ // Last update: Add DexSectionHeader
+ static constexpr uint8_t kVerifierDepsVersion[] = { '0', '1', '9', '\0' };
+
+ // The format version of the dex section header and the dex section, containing
+ // both the dex code and the quickening data.
+ static constexpr uint8_t kDexSectionVersion[] = { '0', '0', '1', '\0' };
+
+ // If the .vdex file has no dex section (hence no dex code nor quickening data),
+ // we encode this magic version.
+ static constexpr uint8_t kDexSectionVersionEmpty[] = { '0', '0', '0', '\0' };
uint8_t magic_[4];
- uint8_t version_[4];
+ uint8_t verifier_deps_version_[4];
+ uint8_t dex_section_version_[4];
uint32_t number_of_dex_files_;
+ uint32_t verifier_deps_size_;
+ };
+
+ struct DexSectionHeader {
+ public:
+ DexSectionHeader(uint32_t dex_size,
+ uint32_t dex_shared_data_size,
+ uint32_t quickening_info_size);
+
+ uint32_t GetDexSize() const { return dex_size_; }
+ uint32_t GetDexSharedDataSize() const { return dex_shared_data_size_; }
+ uint32_t GetQuickeningInfoSize() const { return quickening_info_size_; }
+
+ size_t GetDexSectionSize() const {
+ return sizeof(DexSectionHeader) +
+ GetDexSize() +
+ GetDexSharedDataSize();
+ }
+
+ private:
uint32_t dex_size_;
uint32_t dex_shared_data_size_;
- uint32_t verifier_deps_size_;
uint32_t quickening_info_size_;
- friend class VdexFile;
+ friend class VdexFile; // For updatig quickening_info_size_.
};
+ size_t GetComputedFileSize() const {
+ size_t size = sizeof(VerifierDepsHeader);
+ const VerifierDepsHeader& header = GetVerifierDepsHeader();
+ size += header.GetVerifierDepsSize();
+ size += header.GetSizeOfChecksumsSection();
+ if (header.HasDexSection()) {
+ size += GetDexSectionHeader().GetDexSectionSize();
+ size += GetDexSectionHeader().GetQuickeningInfoSize();
+ }
+ return size;
+ }
+
// Note: The file is called "primary" to match the naming with profiles.
static const constexpr char* kVdexNameInDmFile = "primary.vdex";
@@ -174,24 +218,48 @@ class VdexFile {
const uint8_t* End() const { return mmap_->End(); }
size_t Size() const { return mmap_->Size(); }
- const Header& GetHeader() const {
- return *reinterpret_cast<const Header*>(Begin());
+ const VerifierDepsHeader& GetVerifierDepsHeader() const {
+ return *reinterpret_cast<const VerifierDepsHeader*>(Begin());
+ }
+
+ uint32_t GetDexSectionHeaderOffset() const {
+ return sizeof(VerifierDepsHeader) + GetVerifierDepsHeader().GetSizeOfChecksumsSection();
+ }
+
+ const DexSectionHeader& GetDexSectionHeader() const {
+ DCHECK(GetVerifierDepsHeader().HasDexSection());
+ return *reinterpret_cast<const DexSectionHeader*>(Begin() + GetDexSectionHeaderOffset());
+ }
+
+ const uint8_t* GetVerifierDepsStart() const {
+ const uint8_t* result = Begin() + GetDexSectionHeaderOffset();
+ if (GetVerifierDepsHeader().HasDexSection()) {
+ // When there is a dex section, the verifier deps are after it, but before the quickening.
+ return result + GetDexSectionHeader().GetDexSectionSize();
+ } else {
+ // When there is no dex section, the verifier deps are just after the header.
+ return result;
+ }
}
ArrayRef<const uint8_t> GetVerifierDepsData() const {
return ArrayRef<const uint8_t>(
- DexBegin() + GetHeader().GetDexSize() + GetHeader().GetDexSharedDataSize(),
- GetHeader().GetVerifierDepsSize());
+ GetVerifierDepsStart(),
+ GetVerifierDepsHeader().GetVerifierDepsSize());
}
ArrayRef<const uint8_t> GetQuickeningInfo() const {
- return ArrayRef<const uint8_t>(
- GetVerifierDepsData().data() + GetHeader().GetVerifierDepsSize(),
- GetHeader().GetQuickeningInfoSize());
+ if (GetVerifierDepsHeader().HasDexSection()) {
+ return ArrayRef<const uint8_t>(
+ GetVerifierDepsData().data() + GetVerifierDepsHeader().GetVerifierDepsSize(),
+ GetDexSectionHeader().GetQuickeningInfoSize());
+ } else {
+ return ArrayRef<const uint8_t>();
+ }
}
bool IsValid() const {
- return mmap_->Size() >= sizeof(Header) && GetHeader().IsValid();
+ return mmap_->Size() >= sizeof(VerifierDepsHeader) && GetVerifierDepsHeader().IsValid();
}
// This method is for iterating over the dex files in the vdex. If `cursor` is null,
@@ -202,8 +270,8 @@ class VdexFile {
// Get the location checksum of the dex file number `dex_file_index`.
uint32_t GetLocationChecksum(uint32_t dex_file_index) const {
- DCHECK_LT(dex_file_index, GetHeader().GetNumberOfDexFiles());
- return reinterpret_cast<const uint32_t*>(Begin() + sizeof(Header))[dex_file_index];
+ DCHECK_LT(dex_file_index, GetVerifierDepsHeader().GetNumberOfDexFiles());
+ return reinterpret_cast<const uint32_t*>(Begin() + sizeof(VerifierDepsHeader))[dex_file_index];
}
// Open all the dex files contained in this vdex file.
@@ -228,7 +296,7 @@ class VdexFile {
uint32_t dex_method_idx) const;
bool HasDexSection() const {
- return GetHeader().GetDexSize() != 0;
+ return GetVerifierDepsHeader().HasDexSection();
}
private:
@@ -250,11 +318,13 @@ class VdexFile {
bool ContainsDexFile(const DexFile& dex_file) const;
const uint8_t* DexBegin() const {
- return Begin() + sizeof(Header) + GetHeader().GetSizeOfChecksumsSection();
+ DCHECK(HasDexSection());
+ return Begin() + GetDexSectionHeaderOffset() + sizeof(DexSectionHeader);
}
const uint8_t* DexEnd() const {
- return DexBegin() + GetHeader().GetDexSize();
+ DCHECK(HasDexSection());
+ return DexBegin() + GetDexSectionHeader().GetDexSize();
}
std::unique_ptr<MemMap> mmap_;