summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author David Srbecky <dsrbecky@google.com> 2018-01-10 13:57:04 +0000
committer Gerrit Code Review <noreply-gerritcodereview@google.com> 2018-01-10 13:57:04 +0000
commitf4bf58d9b13972117c640ea1d7bfa6e6dfc189ea (patch)
treea6bdf10f36796c1924e9dca6bfcf1477269c8073
parentd6b7e8c63f8eca25460f56f66dcae15eaa897ff0 (diff)
parentec2cdf4286921131a5f9b3ed12060657ec40f636 (diff)
Merge "Try to mmap vdex file within the address range of the ELF file."
-rw-r--r--build/Android.gtest.mk5
-rw-r--r--compiler/linker/elf_builder.h21
-rw-r--r--dex2oat/dex2oat.cc4
-rw-r--r--dex2oat/linker/elf_writer.h8
-rw-r--r--dex2oat/linker/elf_writer_quick.cc9
-rw-r--r--dex2oat/linker/image_test.h3
-rw-r--r--dex2oat/linker/oat_writer.h4
-rw-r--r--dex2oat/linker/oat_writer_test.cc3
-rw-r--r--oatdump/oatdump.cc3
-rw-r--r--runtime/oat_file.cc68
-rw-r--r--runtime/oat_file.h13
-rw-r--r--runtime/oat_file_test.cc28
-rw-r--r--runtime/vdex_file.cc55
-rw-r--r--runtime/vdex_file.h48
14 files changed, 227 insertions, 45 deletions
diff --git a/build/Android.gtest.mk b/build/Android.gtest.mk
index 1f36cb4e46..45f4e2d4d8 100644
--- a/build/Android.gtest.mk
+++ b/build/Android.gtest.mk
@@ -155,6 +155,11 @@ ART_GTEST_dex2oat_environment_tests_TARGET_DEPS := \
$(TARGET_CORE_IMAGE_interpreter_32) \
patchoatd-target
+ART_GTEST_oat_file_test_HOST_DEPS := \
+ $(ART_GTEST_dex2oat_environment_tests_HOST_DEPS)
+ART_GTEST_oat_file_test_TARGET_DEPS := \
+ $(ART_GTEST_dex2oat_environment_tests_TARGET_DEPS)
+
ART_GTEST_oat_file_assistant_test_HOST_DEPS := \
$(ART_GTEST_dex2oat_environment_tests_HOST_DEPS)
ART_GTEST_oat_file_assistant_test_TARGET_DEPS := \
diff --git a/compiler/linker/elf_builder.h b/compiler/linker/elf_builder.h
index aa3cd98595..5262ab6f3b 100644
--- a/compiler/linker/elf_builder.h
+++ b/compiler/linker/elf_builder.h
@@ -38,9 +38,10 @@ namespace linker {
// Elf_Ehdr - The ELF header.
// Elf_Phdr[] - Program headers for the linker.
// .note.gnu.build-id - Optional build ID section (SHA-1 digest).
-// .rodata - DEX files and oat metadata.
+// .rodata - Oat metadata.
// .text - Compiled code.
// .bss - Zero-initialized writeable section.
+// .dex - Reserved NOBITS space for dex-related data.
// .MIPS.abiflags - MIPS specific section.
// .dynstr - Names for .dynsym.
// .dynsym - A few oat-specific dynamic symbols.
@@ -503,6 +504,7 @@ class ElfBuilder FINAL {
rodata_(this, ".rodata", SHT_PROGBITS, SHF_ALLOC, nullptr, 0, kPageSize, 0),
text_(this, ".text", SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR, nullptr, 0, kPageSize, 0),
bss_(this, ".bss", SHT_NOBITS, SHF_ALLOC, nullptr, 0, kPageSize, 0),
+ dex_(this, ".dex", SHT_NOBITS, SHF_ALLOC, nullptr, 0, kPageSize, 0),
dynstr_(this, ".dynstr", SHF_ALLOC, kPageSize),
dynsym_(this, ".dynsym", SHT_DYNSYM, SHF_ALLOC, &dynstr_),
hash_(this, ".hash", SHT_HASH, SHF_ALLOC, &dynsym_, 0, sizeof(Elf_Word), sizeof(Elf_Word)),
@@ -525,6 +527,7 @@ class ElfBuilder FINAL {
virtual_address_(0) {
text_.phdr_flags_ = PF_R | PF_X;
bss_.phdr_flags_ = PF_R | PF_W;
+ dex_.phdr_flags_ = PF_R;
dynamic_.phdr_flags_ = PF_R | PF_W;
dynamic_.phdr_type_ = PT_DYNAMIC;
eh_frame_hdr_.phdr_type_ = PT_GNU_EH_FRAME;
@@ -538,6 +541,7 @@ class ElfBuilder FINAL {
Section* GetRoData() { return &rodata_; }
Section* GetText() { return &text_; }
Section* GetBss() { return &bss_; }
+ Section* GetDex() { return &dex_; }
StringSection* GetStrTab() { return &strtab_; }
SymbolSection* GetSymTab() { return &symtab_; }
Section* GetEhFrame() { return &eh_frame_; }
@@ -666,7 +670,8 @@ class ElfBuilder FINAL {
Elf_Word text_size,
Elf_Word bss_size,
Elf_Word bss_methods_offset,
- Elf_Word bss_roots_offset) {
+ Elf_Word bss_roots_offset,
+ Elf_Word dex_size) {
std::string soname(elf_file_path);
size_t directory_separator_pos = soname.rfind('/');
if (directory_separator_pos != std::string::npos) {
@@ -679,6 +684,9 @@ class ElfBuilder FINAL {
if (bss_size != 0) {
bss_.AllocateVirtualMemory(bss_size);
}
+ if (dex_size != 0) {
+ dex_.AllocateVirtualMemory(dex_size);
+ }
if (isa_ == InstructionSet::kMips || isa_ == InstructionSet::kMips64) {
abiflags_.AllocateVirtualMemory(abiflags_.GetSize());
}
@@ -725,6 +733,14 @@ class ElfBuilder FINAL {
Elf_Word bsslastword_address = bss_.GetAddress() + bss_size - 4;
dynsym_.Add(oatbsslastword, &bss_, bsslastword_address, 4, STB_GLOBAL, STT_OBJECT);
}
+ if (dex_size != 0u) {
+ Elf_Word oatdex = dynstr_.Add("oatdex");
+ dynsym_.Add(oatdex, &dex_, dex_.GetAddress(), dex_size, STB_GLOBAL, STT_OBJECT);
+ Elf_Word oatdexlastword = dynstr_.Add("oatdexlastword");
+ Elf_Word oatdexlastword_address = dex_.GetAddress() + dex_size - 4;
+ dynsym_.Add(oatdexlastword, &dex_, oatdexlastword_address, 4, STB_GLOBAL, STT_OBJECT);
+ }
+
Elf_Word soname_offset = dynstr_.Add(soname);
// We do not really need a hash-table since there is so few entries.
@@ -967,6 +983,7 @@ class ElfBuilder FINAL {
Section rodata_;
Section text_;
Section bss_;
+ Section dex_;
CachedStringSection dynstr_;
SymbolSection dynsym_;
CachedSection hash_;
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index dabe07f9ce..8d0d89ed5c 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -2015,8 +2015,8 @@ class Dex2Oat FINAL {
text_size,
oat_writer->GetBssSize(),
oat_writer->GetBssMethodsOffset(),
- oat_writer->GetBssRootsOffset());
-
+ oat_writer->GetBssRootsOffset(),
+ oat_writer->GetVdexSize());
if (IsImage()) {
// Update oat layout.
DCHECK(image_writer_ != nullptr);
diff --git a/dex2oat/linker/elf_writer.h b/dex2oat/linker/elf_writer.h
index 0eb36eda0f..a49112bfe6 100644
--- a/dex2oat/linker/elf_writer.h
+++ b/dex2oat/linker/elf_writer.h
@@ -55,11 +55,17 @@ class ElfWriter {
virtual ~ElfWriter() {}
virtual void Start() = 0;
+ // Prepares memory layout of the whole ELF file, and creates dynamic symbols
+ // which point to specific areas of interest (usually section begin and end).
+ // This is needed as multi-image needs to know the memory layout of all ELF
+ // files, before starting to write them.
+ // This method must be called before calling GetLoadedSize().
virtual void PrepareDynamicSection(size_t rodata_size,
size_t text_size,
size_t bss_size,
size_t bss_methods_offset,
- size_t bss_roots_offset) = 0;
+ size_t bss_roots_offset,
+ size_t dex_section_size) = 0;
virtual void PrepareDebugInfo(const ArrayRef<const debug::MethodDebugInfo>& method_infos) = 0;
virtual OutputStream* StartRoData() = 0;
virtual void EndRoData(OutputStream* rodata) = 0;
diff --git a/dex2oat/linker/elf_writer_quick.cc b/dex2oat/linker/elf_writer_quick.cc
index aa64b7d59e..af11d5864d 100644
--- a/dex2oat/linker/elf_writer_quick.cc
+++ b/dex2oat/linker/elf_writer_quick.cc
@@ -99,7 +99,8 @@ class ElfWriterQuick FINAL : public ElfWriter {
size_t text_size,
size_t bss_size,
size_t bss_methods_offset,
- size_t bss_roots_offset) OVERRIDE;
+ size_t bss_roots_offset,
+ size_t dex_section_size) OVERRIDE;
void PrepareDebugInfo(const ArrayRef<const debug::MethodDebugInfo>& method_infos) OVERRIDE;
OutputStream* StartRoData() OVERRIDE;
void EndRoData(OutputStream* rodata) OVERRIDE;
@@ -183,7 +184,8 @@ void ElfWriterQuick<ElfTypes>::PrepareDynamicSection(size_t rodata_size,
size_t text_size,
size_t bss_size,
size_t bss_methods_offset,
- size_t bss_roots_offset) {
+ size_t bss_roots_offset,
+ size_t dex_section_size) {
DCHECK_EQ(rodata_size_, 0u);
rodata_size_ = rodata_size;
DCHECK_EQ(text_size_, 0u);
@@ -195,7 +197,8 @@ void ElfWriterQuick<ElfTypes>::PrepareDynamicSection(size_t rodata_size,
text_size_,
bss_size_,
bss_methods_offset,
- bss_roots_offset);
+ bss_roots_offset,
+ dex_section_size);
}
template <typename ElfTypes>
diff --git a/dex2oat/linker/image_test.h b/dex2oat/linker/image_test.h
index 85145d3d64..067111824a 100644
--- a/dex2oat/linker/image_test.h
+++ b/dex2oat/linker/image_test.h
@@ -316,7 +316,8 @@ inline void CompilationHelper::Compile(CompilerDriver* driver,
text_size,
oat_writer->GetBssSize(),
oat_writer->GetBssMethodsOffset(),
- oat_writer->GetBssRootsOffset());
+ oat_writer->GetBssRootsOffset(),
+ oat_writer->GetVdexSize());
writer->UpdateOatFileLayout(i,
elf_writer->GetLoadedSize(),
diff --git a/dex2oat/linker/oat_writer.h b/dex2oat/linker/oat_writer.h
index ba29e3b3a2..c9deea9a4b 100644
--- a/dex2oat/linker/oat_writer.h
+++ b/dex2oat/linker/oat_writer.h
@@ -230,6 +230,10 @@ class OatWriter {
return bss_roots_offset_;
}
+ size_t GetVdexSize() const {
+ return vdex_size_;
+ }
+
size_t GetOatDataOffset() const {
return oat_data_offset_;
}
diff --git a/dex2oat/linker/oat_writer_test.cc b/dex2oat/linker/oat_writer_test.cc
index 488806092b..99bc1adabb 100644
--- a/dex2oat/linker/oat_writer_test.cc
+++ b/dex2oat/linker/oat_writer_test.cc
@@ -219,7 +219,8 @@ class OatTest : public CommonCompilerTest {
text_size,
oat_writer.GetBssSize(),
oat_writer.GetBssMethodsOffset(),
- oat_writer.GetBssRootsOffset());
+ oat_writer.GetBssRootsOffset(),
+ oat_writer.GetVdexSize());
std::unique_ptr<BufferedOutputStream> vdex_out =
std::make_unique<BufferedOutputStream>(std::make_unique<FileOutputStream>(vdex_file));
diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc
index ca8077fea1..6668dace89 100644
--- a/oatdump/oatdump.cc
+++ b/oatdump/oatdump.cc
@@ -171,7 +171,8 @@ class OatSymbolizer FINAL {
text_size,
oat_file_->BssSize(),
oat_file_->BssMethodsOffset(),
- oat_file_->BssRootsOffset());
+ oat_file_->BssRootsOffset(),
+ oat_file_->VdexSize());
builder_->WriteDynamicSection();
const OatHeader& oat_header = oat_file_->GetOatHeader();
diff --git a/runtime/oat_file.cc b/runtime/oat_file.cc
index df07a191bc..8548d2c67d 100644
--- a/runtime/oat_file.cc
+++ b/runtime/oat_file.cc
@@ -194,10 +194,6 @@ OatFileBase* OatFileBase::OpenOatFile(const std::string& vdex_filename,
ret->PreLoad();
- if (!ret->LoadVdex(vdex_filename, writable, low_4gb, error_msg)) {
- return nullptr;
- }
-
if (!ret->Load(elf_filename,
oat_file_begin,
writable,
@@ -211,6 +207,10 @@ OatFileBase* OatFileBase::OpenOatFile(const std::string& vdex_filename,
return nullptr;
}
+ if (!ret->LoadVdex(vdex_filename, writable, low_4gb, error_msg)) {
+ return nullptr;
+ }
+
ret->PreSetup(elf_filename);
if (!ret->Setup(abs_dex_location, error_msg)) {
@@ -234,10 +234,6 @@ OatFileBase* OatFileBase::OpenOatFile(int vdex_fd,
std::string* error_msg) {
std::unique_ptr<OatFileBase> ret(new kOatFileBaseSubType(oat_location, executable));
- if (!ret->LoadVdex(vdex_fd, vdex_location, writable, low_4gb, error_msg)) {
- return nullptr;
- }
-
if (!ret->Load(oat_fd,
oat_file_begin,
writable,
@@ -251,6 +247,10 @@ OatFileBase* OatFileBase::OpenOatFile(int vdex_fd,
return nullptr;
}
+ if (!ret->LoadVdex(vdex_fd, vdex_location, writable, low_4gb, error_msg)) {
+ return nullptr;
+ }
+
ret->PreSetup(oat_location);
if (!ret->Setup(abs_dex_location, error_msg)) {
@@ -264,7 +264,14 @@ bool OatFileBase::LoadVdex(const std::string& vdex_filename,
bool writable,
bool low_4gb,
std::string* error_msg) {
- vdex_ = VdexFile::Open(vdex_filename, writable, low_4gb, /* unquicken*/ false, error_msg);
+ vdex_ = VdexFile::OpenAtAddress(vdex_begin_,
+ vdex_end_ - vdex_begin_,
+ true /* mmap_reuse */,
+ vdex_filename,
+ writable,
+ low_4gb,
+ /* unquicken*/ false,
+ error_msg);
if (vdex_.get() == nullptr) {
*error_msg = StringPrintf("Failed to load vdex file '%s' %s",
vdex_filename.c_str(),
@@ -285,13 +292,16 @@ bool OatFileBase::LoadVdex(int vdex_fd,
if (rc == -1) {
PLOG(WARNING) << "Failed getting length of vdex file";
} else {
- vdex_ = VdexFile::Open(vdex_fd,
- s.st_size,
- vdex_filename,
- writable,
- low_4gb,
- false /* unquicken */,
- error_msg);
+ vdex_ = VdexFile::OpenAtAddress(vdex_begin_,
+ vdex_end_ - vdex_begin_,
+ true /* mmap_reuse */,
+ vdex_fd,
+ s.st_size,
+ vdex_filename,
+ writable,
+ low_4gb,
+ false /* unquicken */,
+ error_msg);
if (vdex_.get() == nullptr) {
*error_msg = "Failed opening vdex file.";
return false;
@@ -339,7 +349,7 @@ bool OatFileBase::ComputeFields(uint8_t* requested_base,
} else {
bss_end_ = const_cast<uint8_t*>(FindDynamicSymbolAddress("oatbsslastword", &symbol_error_msg));
if (bss_end_ == nullptr) {
- *error_msg = StringPrintf("Failed to find oatbasslastword symbol in '%s'", file_path.c_str());
+ *error_msg = StringPrintf("Failed to find oatbsslastword symbol in '%s'", file_path.c_str());
return false;
}
// Readjust to be non-inclusive upper bound.
@@ -351,6 +361,20 @@ bool OatFileBase::ComputeFields(uint8_t* requested_base,
bss_roots_ = const_cast<uint8_t*>(FindDynamicSymbolAddress("oatbssroots", &symbol_error_msg));
}
+ vdex_begin_ = const_cast<uint8_t*>(FindDynamicSymbolAddress("oatdex", &symbol_error_msg));
+ if (vdex_begin_ == nullptr) {
+ // No .vdex section.
+ vdex_end_ = nullptr;
+ } else {
+ vdex_end_ = const_cast<uint8_t*>(FindDynamicSymbolAddress("oatdexlastword", &symbol_error_msg));
+ if (vdex_end_ == nullptr) {
+ *error_msg = StringPrintf("Failed to find oatdexlastword symbol in '%s'", file_path.c_str());
+ return false;
+ }
+ // Readjust to be non-inclusive upper bound.
+ vdex_end_ += sizeof(uint32_t);
+ }
+
return true;
}
@@ -1441,6 +1465,8 @@ OatFile::OatFile(const std::string& location, bool is_executable)
bss_methods_(nullptr),
bss_roots_(nullptr),
is_executable_(is_executable),
+ vdex_begin_(nullptr),
+ vdex_end_(nullptr),
secondary_lookup_lock_("OatFile secondary lookup lock", kOatFileSecondaryLookupLock) {
CHECK(!location_.empty());
}
@@ -1471,6 +1497,14 @@ const uint8_t* OatFile::BssEnd() const {
return bss_end_;
}
+const uint8_t* OatFile::VdexBegin() const {
+ return vdex_begin_;
+}
+
+const uint8_t* OatFile::VdexEnd() const {
+ return vdex_end_;
+}
+
const uint8_t* OatFile::DexBegin() const {
return vdex_->Begin();
}
diff --git a/runtime/oat_file.h b/runtime/oat_file.h
index 02318b68b7..e9f7edca61 100644
--- a/runtime/oat_file.h
+++ b/runtime/oat_file.h
@@ -279,6 +279,10 @@ class OatFile {
return BssEnd() - BssBegin();
}
+ size_t VdexSize() const {
+ return VdexEnd() - VdexBegin();
+ }
+
size_t BssMethodsOffset() const {
// Note: This is used only for symbolizer and needs to return a valid .bss offset.
return (bss_methods_ != nullptr) ? bss_methods_ - BssBegin() : BssRootsOffset();
@@ -299,6 +303,9 @@ class OatFile {
const uint8_t* BssBegin() const;
const uint8_t* BssEnd() const;
+ const uint8_t* VdexBegin() const;
+ const uint8_t* VdexEnd() const;
+
const uint8_t* DexBegin() const;
const uint8_t* DexEnd() const;
@@ -358,6 +365,12 @@ class OatFile {
// Was this oat_file loaded executable?
const bool is_executable_;
+ // Pointer to the .vdex section, if present, otherwise null.
+ uint8_t* vdex_begin_;
+
+ // Pointer to the end of the .vdex section, if present, otherwise null.
+ uint8_t* vdex_end_;
+
// Owning storage for the OatDexFile objects.
std::vector<const OatDexFile*> oat_dex_files_storage_;
diff --git a/runtime/oat_file_test.cc b/runtime/oat_file_test.cc
index 7bf0f84596..8d864018ab 100644
--- a/runtime/oat_file_test.cc
+++ b/runtime/oat_file_test.cc
@@ -21,11 +21,13 @@
#include <gtest/gtest.h>
#include "common_runtime_test.h"
+#include "dexopt_test.h"
#include "scoped_thread_state_change-inl.h"
+#include "vdex_file.h"
namespace art {
-class OatFileTest : public CommonRuntimeTest {
+class OatFileTest : public DexoptTest {
};
TEST_F(OatFileTest, ResolveRelativeEncodedDexLocation) {
@@ -62,4 +64,28 @@ TEST_F(OatFileTest, ResolveRelativeEncodedDexLocation) {
"/data/app/foo/base.apk", "o/base.apk"));
}
+TEST_F(OatFileTest, LoadOat) {
+ std::string dex_location = GetScratchDir() + "/LoadOat.jar";
+
+ Copy(GetDexSrc1(), dex_location);
+ GenerateOatForTest(dex_location.c_str(), CompilerFilter::kSpeed);
+
+ std::string oat_location;
+ std::string error_msg;
+ ASSERT_TRUE(OatFileAssistant::DexLocationToOatFilename(
+ dex_location, kRuntimeISA, &oat_location, &error_msg)) << error_msg;
+ std::unique_ptr<OatFile> odex_file(OatFile::Open(oat_location.c_str(),
+ oat_location.c_str(),
+ nullptr,
+ nullptr,
+ false,
+ /*low_4gb*/false,
+ dex_location.c_str(),
+ &error_msg));
+ ASSERT_TRUE(odex_file.get() != nullptr);
+
+ // Check that the vdex file was loaded in the reserved space of odex file.
+ EXPECT_EQ(odex_file->GetVdexFile()->Begin(), odex_file->VdexBegin());
+}
+
} // namespace art
diff --git a/runtime/vdex_file.cc b/runtime/vdex_file.cc
index a53556ffcc..b6dd2f0123 100644
--- a/runtime/vdex_file.cc
+++ b/runtime/vdex_file.cc
@@ -57,11 +57,14 @@ VdexFile::Header::Header(uint32_t number_of_dex_files,
DCHECK(IsVersionValid());
}
-std::unique_ptr<VdexFile> VdexFile::Open(const std::string& vdex_filename,
- bool writable,
- bool low_4gb,
- bool unquicken,
- std::string* error_msg) {
+std::unique_ptr<VdexFile> VdexFile::OpenAtAddress(uint8_t* mmap_addr,
+ size_t mmap_size,
+ bool mmap_reuse,
+ const std::string& vdex_filename,
+ bool writable,
+ bool low_4gb,
+ bool unquicken,
+ std::string* error_msg) {
if (!OS::FileExists(vdex_filename.c_str())) {
*error_msg = "File " + vdex_filename + " does not exist.";
return nullptr;
@@ -85,23 +88,47 @@ std::unique_ptr<VdexFile> VdexFile::Open(const std::string& vdex_filename,
return nullptr;
}
- return Open(vdex_file->Fd(), vdex_length, vdex_filename, writable, low_4gb, unquicken, error_msg);
+ return OpenAtAddress(mmap_addr,
+ mmap_size,
+ mmap_reuse,
+ vdex_file->Fd(),
+ vdex_length,
+ vdex_filename,
+ writable,
+ low_4gb,
+ unquicken,
+ error_msg);
}
-std::unique_ptr<VdexFile> VdexFile::Open(int file_fd,
- size_t vdex_length,
- const std::string& vdex_filename,
- bool writable,
- bool low_4gb,
- bool unquicken,
- std::string* error_msg) {
- std::unique_ptr<MemMap> mmap(MemMap::MapFile(
+std::unique_ptr<VdexFile> VdexFile::OpenAtAddress(uint8_t* mmap_addr,
+ size_t mmap_size,
+ bool mmap_reuse,
+ int file_fd,
+ size_t vdex_length,
+ const std::string& vdex_filename,
+ bool writable,
+ bool low_4gb,
+ bool unquicken,
+ std::string* error_msg) {
+ if (low_4gb) {
+ LOG(WARNING) << "Can not mmap vdex in low 4GB"; // TODO: Implement in MemMap.
+ mmap_addr = nullptr;
+ mmap_reuse = false;
+ }
+ if (mmap_addr != nullptr && mmap_size < vdex_length) {
+ LOG(WARNING) << "Insufficient pre-allocated space to mmap vdex.";
+ mmap_addr = nullptr;
+ mmap_reuse = false;
+ }
+ std::unique_ptr<MemMap> mmap(MemMap::MapFileAtAddress(
+ mmap_addr,
vdex_length,
(writable || unquicken) ? PROT_READ | PROT_WRITE : PROT_READ,
unquicken ? MAP_PRIVATE : MAP_SHARED,
file_fd,
0 /* start offset */,
low_4gb,
+ mmap_reuse,
vdex_filename.c_str(),
error_msg));
if (mmap == nullptr) {
diff --git a/runtime/vdex_file.h b/runtime/vdex_file.h
index 2d9fcab59c..f78335d347 100644
--- a/runtime/vdex_file.h
+++ b/runtime/vdex_file.h
@@ -102,11 +102,44 @@ class VdexFile {
explicit VdexFile(MemMap* mmap) : mmap_(mmap) {}
// Returns nullptr if the vdex file cannot be opened or is not valid.
+ // The mmap_* parameters can be left empty (nullptr/0/false) to allocate at random address.
+ static std::unique_ptr<VdexFile> OpenAtAddress(uint8_t* mmap_addr,
+ size_t mmap_size,
+ bool mmap_reuse,
+ const std::string& vdex_filename,
+ bool writable,
+ bool low_4gb,
+ bool unquicken,
+ std::string* error_msg);
+
+ // Returns nullptr if the vdex file cannot be opened or is not valid.
+ // The mmap_* parameters can be left empty (nullptr/0/false) to allocate at random address.
+ static std::unique_ptr<VdexFile> OpenAtAddress(uint8_t* mmap_addr,
+ size_t mmap_size,
+ bool mmap_reuse,
+ int file_fd,
+ size_t vdex_length,
+ const std::string& vdex_filename,
+ bool writable,
+ bool low_4gb,
+ bool unquicken,
+ std::string* error_msg);
+
+ // Returns nullptr if the vdex file cannot be opened or is not valid.
static std::unique_ptr<VdexFile> Open(const std::string& vdex_filename,
bool writable,
bool low_4gb,
bool unquicken,
- std::string* error_msg);
+ std::string* error_msg) {
+ return OpenAtAddress(nullptr,
+ 0,
+ false,
+ vdex_filename,
+ writable,
+ low_4gb,
+ unquicken,
+ error_msg);
+ }
// Returns nullptr if the vdex file cannot be opened or is not valid.
static std::unique_ptr<VdexFile> Open(int file_fd,
@@ -115,7 +148,18 @@ class VdexFile {
bool writable,
bool low_4gb,
bool unquicken,
- std::string* error_msg);
+ std::string* error_msg) {
+ return OpenAtAddress(nullptr,
+ 0,
+ false,
+ file_fd,
+ vdex_length,
+ vdex_filename,
+ writable,
+ low_4gb,
+ unquicken,
+ error_msg);
+ }
const uint8_t* Begin() const { return mmap_->Begin(); }
const uint8_t* End() const { return mmap_->End(); }