Use provided dex filenames in oat file.

Remove OatFile::RemoveRelativeEncodedDexFileLocation() and
use the provided `dex_filenames' (see below) if not empty,
without checking for prefix match or host/target build type.

Also add extra primary/multi-dex location checking when
opening an oat file. Since some tests were already creating
oat files from multiple dex files, rewrite the interface to
better support that option, replacing the old argument
`abs_dex_location` with `dex_filenames` that can provide
paths to multiple dex files.

Test: m test-art-host
Test: testrunner.py --host --optimizing
Test: aosp_taimen-userdebug boots.
Change-Id: I36a9abca72872c41e4c10fdacbeadf551ca740dc
diff --git a/dex2oat/dex2oat_test.cc b/dex2oat/dex2oat_test.cc
index bd439b7..7ff9b73 100644
--- a/dex2oat/dex2oat_test.cc
+++ b/dex2oat/dex2oat_test.cc
@@ -168,8 +168,7 @@
                                                        odex_location.c_str(),
                                                        /*executable=*/ false,
                                                        /*low_4gb=*/ false,
-                                                       dex_location.c_str(),
-                                                       /*reservation=*/ nullptr,
+                                                       dex_location,
                                                        &error_msg));
       if (odex_file == nullptr) {
         return ::testing::AssertionFailure() << "Could not open odex file: " << error_msg;
@@ -191,8 +190,7 @@
                                                          odex_location.c_str(),
                                                          /*executable=*/ false,
                                                          /*low_4gb=*/ false,
-                                                         dex_location.c_str(),
-                                                         /*reservation=*/ nullptr,
+                                                         dex_location,
                                                          &error_msg));
         if (odex_file != nullptr) {
           return ::testing::AssertionFailure() << "Could open odex file: " << error_msg;
@@ -533,8 +531,7 @@
                                                      odex_location.c_str(),
                                                      /*executable=*/ false,
                                                      /*low_4gb=*/ false,
-                                                     dex_location.c_str(),
-                                                     /*reservation=*/ nullptr,
+                                                     dex_location,
                                                      &error_msg));
     ASSERT_TRUE(odex_file.get() != nullptr) << error_msg;
     EXPECT_GT(app_image_file.length(), 0u);
@@ -803,8 +800,7 @@
                                                      odex_location.c_str(),
                                                      /*executable=*/ false,
                                                      /*low_4gb=*/ false,
-                                                     dex_location.c_str(),
-                                                     /*reservation=*/ nullptr,
+                                                     dex_location,
                                                      &error_msg));
     ASSERT_TRUE(odex_file.get() != nullptr) << error_msg;
 
@@ -964,8 +960,7 @@
                                                      odex_location.c_str(),
                                                      /*executable=*/ false,
                                                      /*low_4gb=*/ false,
-                                                     dex_location.c_str(),
-                                                     /*reservation=*/ nullptr,
+                                                     dex_location,
                                                      &error_msg));
     ASSERT_TRUE(odex_file.get() != nullptr) << error_msg;
     ASSERT_GE(odex_file->GetOatDexFiles().size(), 1u);
@@ -1410,8 +1405,7 @@
                                                    oat_filename.c_str(),
                                                    /*executable=*/ false,
                                                    /*low_4gb=*/ false,
-                                                   dex->GetLocation().c_str(),
-                                                   /*reservation=*/ nullptr,
+                                                   dex->GetLocation(),
                                                    &error_msg));
   ASSERT_TRUE(odex_file != nullptr);
   std::vector<const OatDexFile*> oat_dex_files = odex_file->GetOatDexFiles();
@@ -1519,8 +1513,7 @@
                                                    oat_filename.c_str(),
                                                    /*executable=*/ false,
                                                    /*low_4gb=*/ false,
-                                                   dex_location.c_str(),
-                                                   /*reservation=*/ nullptr,
+                                                   dex_location,
                                                    &error_msg));
   ASSERT_TRUE(odex_file != nullptr);
   std::vector<const OatDexFile*> oat_dex_files = odex_file->GetOatDexFiles();
@@ -1783,8 +1776,7 @@
                                                    oat_filename.c_str(),
                                                    /*executable=*/ false,
                                                    /*low_4gb=*/ false,
-                                                   temp_dex.GetFilename().c_str(),
-                                                   /*reservation=*/ nullptr,
+                                                   temp_dex.GetFilename(),
                                                    &error_msg));
   ASSERT_TRUE(odex_file != nullptr);
   std::vector<const OatDexFile*> oat_dex_files = odex_file->GetOatDexFiles();
@@ -1860,8 +1852,7 @@
                                                    odex_location.c_str(),
                                                    /*executable=*/ false,
                                                    /*low_4gb=*/ false,
-                                                   dex_location.c_str(),
-                                                   /*reservation=*/ nullptr,
+                                                   dex_location,
                                                    &error_msg));
   ASSERT_TRUE(odex_file != nullptr);
   ASSERT_STREQ("install", odex_file->GetCompilationReason());
@@ -1885,8 +1876,7 @@
                                                    odex_location.c_str(),
                                                    /*executable=*/ false,
                                                    /*low_4gb=*/ false,
-                                                   dex_location.c_str(),
-                                                   /*reservation=*/ nullptr,
+                                                   dex_location,
                                                    &error_msg));
   ASSERT_TRUE(odex_file != nullptr);
   ASSERT_EQ(nullptr, odex_file->GetCompilationReason());
@@ -1922,8 +1912,7 @@
                                                    odex_location.c_str(),
                                                    /*executable=*/ false,
                                                    /*low_4gb=*/ false,
-                                                   dex_location.c_str(),
-                                                   /*reservation=*/ nullptr,
+                                                   dex_location,
                                                    &error_msg));
   ASSERT_TRUE(odex_file != nullptr) << dex_location;
   std::vector<const OatDexFile*> oat_dex_files = odex_file->GetOatDexFiles();
@@ -2165,8 +2154,6 @@
                                                    odex_location.c_str(),
                                                    /*executable=*/ false,
                                                    /*low_4gb=*/ false,
-                                                   odex_location.c_str(),
-                                                   /*reservation=*/ nullptr,
                                                    &error_msg));
   ASSERT_TRUE(odex_file != nullptr);
   ImageHeader header = {};
@@ -2278,8 +2265,6 @@
                                                    odex_location.c_str(),
                                                    /*executable=*/ false,
                                                    /*low_4gb=*/ false,
-                                                   odex_location.c_str(),
-                                                   /*reservation=*/ nullptr,
                                                    &error_msg));
   ASSERT_TRUE(odex_file != nullptr);
   // Check the strings in the app image intern table only contain the "startup" strigs.
diff --git a/dex2oat/linker/oat_writer_test.cc b/dex2oat/linker/oat_writer_test.cc
index 0a43bfc..20d87fa 100644
--- a/dex2oat/linker/oat_writer_test.cc
+++ b/dex2oat/linker/oat_writer_test.cc
@@ -414,8 +414,6 @@
                                                   tmp_oat.GetFilename(),
                                                   /*executable=*/ false,
                                                   /*low_4gb=*/ true,
-                                                  /*abs_dex_location=*/ nullptr,
-                                                  /*reservation=*/ nullptr,
                                                   &error_msg));
   ASSERT_TRUE(oat_file.get() != nullptr) << error_msg;
   const OatHeader& oat_header = oat_file->GetOatHeader();
@@ -533,8 +531,6 @@
                                                   tmp_oat.GetFilename(),
                                                   /*executable=*/ false,
                                                   /*low_4gb=*/ false,
-                                                  /*abs_dex_location=*/ nullptr,
-                                                  /*reservation=*/ nullptr,
                                                   &error_msg));
   ASSERT_TRUE(oat_file != nullptr);
   EXPECT_LT(static_cast<size_t>(oat_file->Size()),
@@ -610,8 +606,6 @@
                                                          tmp_oat.GetFilename(),
                                                          /*executable=*/ false,
                                                          low_4gb,
-                                                         /*abs_dex_location=*/ nullptr,
-                                                         /*reservation=*/ nullptr,
                                                          &error_msg));
   ASSERT_TRUE(opened_oat_file != nullptr) << error_msg;
   if (low_4gb) {
@@ -740,8 +734,6 @@
                                                              tmp_oat.GetFilename(),
                                                              /*executable=*/ false,
                                                              /*low_4gb=*/ false,
-                                                             /*abs_dex_location=*/ nullptr,
-                                                             /*reservation=*/ nullptr,
                                                              &error_msg));
       ASSERT_TRUE(opened_oat_file != nullptr) << error_msg;
       ASSERT_EQ(2u, opened_oat_file->GetOatDexFiles().size());
@@ -790,8 +782,6 @@
                                                              tmp_oat.GetFilename(),
                                                              /*executable=*/ false,
                                                              /*low_4gb=*/ false,
-                                                             /*abs_dex_location=*/ nullptr,
-                                                             /*reservation=*/ nullptr,
                                                              &error_msg));
       ASSERT_TRUE(opened_oat_file != nullptr) << error_msg;
       ASSERT_EQ(2u, opened_oat_file->GetOatDexFiles().size());
diff --git a/dexlayout/dexdiag_test.cc b/dexlayout/dexdiag_test.cc
index 23fd66f..9cf0f07 100644
--- a/dexlayout/dexdiag_test.cc
+++ b/dexlayout/dexdiag_test.cc
@@ -68,8 +68,6 @@
                                                oat_location.c_str(),
                                                /*executable=*/ false,
                                                /*low_4gb=*/ false,
-                                               /*abs_dex_location=*/ nullptr,
-                                               /*reservation=*/ nullptr,
                                                &error_msg));
     EXPECT_TRUE(oat != nullptr) << error_msg;
     return oat;
diff --git a/libartbase/base/array_ref.h b/libartbase/base/array_ref.h
index 1d7bde6..e8b3bce 100644
--- a/libartbase/base/array_ref.h
+++ b/libartbase/base/array_ref.h
@@ -70,8 +70,8 @@
       : array_(array), size_(size) {
   }
 
-  constexpr ArrayRef(T* array_in, size_t size_in)
-      : array_(array_in), size_(size_in) {
+  constexpr ArrayRef(T* array, size_t size)
+      : array_(array), size_(size) {
   }
 
   template <typename Vector,
diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc
index 95f085c..cfecb61 100644
--- a/oatdump/oatdump.cc
+++ b/oatdump/oatdump.cc
@@ -1889,8 +1889,6 @@
                                oat_location,
                                /*executable=*/ false,
                                /*low_4gb=*/ false,
-                               /*abs_dex_location=*/ nullptr,
-                               /*reservation=*/ nullptr,
                                &error_msg);
     }
     if (oat_file == nullptr) {
@@ -2770,8 +2768,6 @@
                                                     options->app_oat_,
                                                     /*executable=*/ false,
                                                     /*low_4gb=*/ true,
-                                                    /*abs_dex_location=*/ nullptr,
-                                                    /*reservation=*/ nullptr,
                                                     &error_msg));
     if (oat_file == nullptr) {
       LOG(ERROR) << "Failed to open oat file " << options->app_oat_ << " with error " << error_msg;
@@ -2889,13 +2885,16 @@
     LOG(WARNING) << "No dex filename provided, "
                  << "oatdump might fail if the oat file does not contain the dex code.";
   }
+  std::string dex_filename_str((dex_filename != nullptr) ? dex_filename : "");
+  ArrayRef<const std::string> dex_filenames(&dex_filename_str,
+                                            /*size=*/ (dex_filename != nullptr) ? 1u : 0u);
   std::string error_msg;
   std::unique_ptr<OatFile> oat_file(OatFile::Open(/*zip_fd=*/ -1,
                                                   oat_filename,
                                                   oat_filename,
                                                   /*executable=*/ false,
                                                   /*low_4gb=*/ false,
-                                                  dex_filename,
+                                                  dex_filenames,
                                                   /*reservation=*/ nullptr,
                                                   &error_msg));
   if (oat_file == nullptr) {
@@ -2914,13 +2913,16 @@
                         const char* dex_filename,
                         std::string& output_name,
                         bool no_bits) {
+  std::string dex_filename_str((dex_filename != nullptr) ? dex_filename : "");
+  ArrayRef<const std::string> dex_filenames(&dex_filename_str,
+                                            /*size=*/ (dex_filename != nullptr) ? 1u : 0u);
   std::string error_msg;
   std::unique_ptr<OatFile> oat_file(OatFile::Open(/*zip_fd=*/ -1,
                                                   oat_filename,
                                                   oat_filename,
                                                   /*executable=*/ false,
                                                   /*low_4gb=*/ false,
-                                                  dex_filename,
+                                                  dex_filenames,
                                                   /*reservation=*/ nullptr,
                                                   &error_msg));
   if (oat_file == nullptr) {
@@ -2961,13 +2963,16 @@
     std::vector<const DexFile*> class_path;
 
     if (oat_filename != nullptr) {
+    std::string dex_filename_str((dex_filename != nullptr) ? dex_filename : "");
+    ArrayRef<const std::string> dex_filenames(&dex_filename_str,
+                                              /*size=*/ (dex_filename != nullptr) ? 1u : 0u);
       std::string error_msg;
       std::unique_ptr<OatFile> oat_file(OatFile::Open(/*zip_fd=*/ -1,
                                                       oat_filename,
                                                       oat_filename,
                                                       /*executable=*/ false,
                                                       /*low_4gb=*/false,
-                                                      dex_filename,
+                                                      dex_filenames,
                                                       /*reservation=*/ nullptr,
                                                       &error_msg));
       if (oat_file == nullptr) {
diff --git a/runtime/dexopt_test.cc b/runtime/dexopt_test.cc
index 4f438e7..afbd053 100644
--- a/runtime/dexopt_test.cc
+++ b/runtime/dexopt_test.cc
@@ -111,8 +111,7 @@
                                                    oat_location.c_str(),
                                                    /*executable=*/ false,
                                                    /*low_4gb=*/ false,
-                                                   dex_location.c_str(),
-                                                   /*reservation=*/ nullptr,
+                                                   dex_location,
                                                    &error_msg));
   ASSERT_TRUE(odex_file.get() != nullptr) << error_msg;
   EXPECT_EQ(filter, odex_file->GetCompilerFilter());
diff --git a/runtime/gc/space/image_space.cc b/runtime/gc/space/image_space.cc
index 332451a..11e5b45 100644
--- a/runtime/gc/space/image_space.cc
+++ b/runtime/gc/space/image_space.cc
@@ -2584,7 +2584,7 @@
   }
 
   bool OpenOatFile(ImageSpace* space,
-                   const std::string& dex_filename,
+                   ArrayRef<const std::string> dex_filenames,
                    bool validate_oat_file,
                    ArrayRef<const std::unique_ptr<ImageSpace>> dependencies,
                    TimingLogger* logger,
@@ -2609,7 +2609,7 @@
                                    oat_location,
                                    executable_,
                                    /*low_4gb=*/ false,
-                                   /*abs_dex_location=*/ dex_filename.c_str(),
+                                   dex_filenames,
                                    image_reservation,
                                    error_msg));
       if (oat_file == nullptr) {
@@ -2783,7 +2783,7 @@
     for (std::size_t i = 0u, size = locations.size(); i != size; ++i) {
       ImageSpace* space = (*spaces)[spaces->size() - chunk.component_count + i].get();
       if (!OpenOatFile(space,
-                       boot_class_path_[chunk.start_index + i],
+                       boot_class_path_.SubArray(/*pos=*/ chunk.start_index + i, /*length=*/ 1u),
                        validate_oat_file,
                        dependencies,
                        logger,
@@ -3444,9 +3444,7 @@
         size_t num_dex_files = oat_file->GetOatDexFiles().size();
         CHECK_NE(num_dex_files, 0u);
         const std::string main_location = oat_file->GetOatDexFiles()[0]->GetDexFileLocation();
-        // TODO: Get rid of the weird ResolveRelativeEncodedDexLocation() stuff from oat_file.cc
-        // and enable this check:
-        // CHECK_EQ(main_location, boot_class_path_locations[image_pos + component_index]);
+        CHECK_EQ(main_location, boot_class_path_locations[image_pos + component_index]);
         CHECK(!DexFileLoader::IsMultiDexLocation(main_location.c_str()));
         for (size_t i = 1u; i != num_dex_files; ++i) {
           CHECK(DexFileLoader::IsMultiDexLocation(
diff --git a/runtime/gc/space/image_space_test.cc b/runtime/gc/space/image_space_test.cc
index 008793b..580b490 100644
--- a/runtime/gc/space/image_space_test.cc
+++ b/runtime/gc/space/image_space_test.cc
@@ -51,11 +51,23 @@
                                              oat_location.c_str(),
                                              /*executable=*/ false,
                                              /*low_4gb=*/ false,
-                                             /*abs_dex_location=*/ nullptr,
-                                             /*reservation=*/ nullptr,
                                              &error_msg));
   ASSERT_TRUE(oat != nullptr) << error_msg;
 
+  {
+    // Test opening the oat file also with explicit dex filenames.
+    std::vector<std::string> dex_filenames{ dex1, multidex1, dex2 };
+    std::unique_ptr<OatFile> oat2(OatFile::Open(/*zip_fd=*/ -1,
+                                                oat_location.c_str(),
+                                                oat_location.c_str(),
+                                                /*executable=*/ false,
+                                                /*low_4gb=*/ false,
+                                                ArrayRef<const std::string>(dex_filenames),
+                                                /*reservation=*/ nullptr,
+                                                &error_msg));
+    ASSERT_TRUE(oat2 != nullptr) << error_msg;
+  }
+
   // Originally all the dex checksums should be up to date.
   EXPECT_TRUE(ImageSpace::ValidateOatFile(*oat, &error_msg)) << error_msg;
 
diff --git a/runtime/oat_file.cc b/runtime/oat_file.cc
index 9ef5fbb..30ba6dd 100644
--- a/runtime/oat_file.cc
+++ b/runtime/oat_file.cc
@@ -45,6 +45,7 @@
 #include "base/mem_map.h"
 #include "base/os.h"
 #include "base/stl_util.h"
+#include "base/string_view_cpp20.h"
 #include "base/systrace.h"
 #include "base/unix_file/fd_file.h"
 #include "base/utils.h"
@@ -110,7 +111,7 @@
                                   bool writable,
                                   bool executable,
                                   bool low_4gb,
-                                  const char* abs_dex_location,
+                                  ArrayRef<const std::string> dex_filenames,
                                   /*inout*/MemMap* reservation,  // Where to load if not null.
                                   /*out*/std::string* error_msg);
 
@@ -123,7 +124,7 @@
                                   bool writable,
                                   bool executable,
                                   bool low_4gb,
-                                  const char* abs_dex_location,
+                                  ArrayRef<const std::string> dex_filenames,
                                   /*inout*/MemMap* reservation,  // Where to load if not null.
                                   /*out*/std::string* error_msg);
 
@@ -164,7 +165,7 @@
 
   virtual void PreSetup(const std::string& elf_filename) = 0;
 
-  bool Setup(int zip_fd, const char* abs_dex_location, std::string* error_msg);
+  bool Setup(int zip_fd, ArrayRef<const std::string> dex_filenames, std::string* error_msg);
   bool Setup(const std::vector<const DexFile*>& dex_files);
 
   // Setters exposed for ElfOatFile.
@@ -193,7 +194,7 @@
                                       bool writable,
                                       bool executable,
                                       bool low_4gb,
-                                      const char* abs_dex_location,
+                                      ArrayRef<const std::string> dex_filenames,
                                       /*inout*/MemMap* reservation,
                                       /*out*/std::string* error_msg) {
   std::unique_ptr<OatFileBase> ret(new kOatFileBaseSubType(location, executable));
@@ -219,7 +220,7 @@
     return nullptr;
   }
 
-  if (!ret->Setup(zip_fd, abs_dex_location, error_msg)) {
+  if (!ret->Setup(zip_fd, dex_filenames, error_msg)) {
     return nullptr;
   }
 
@@ -235,7 +236,7 @@
                                       bool writable,
                                       bool executable,
                                       bool low_4gb,
-                                      const char* abs_dex_location,
+                                      ArrayRef<const std::string> dex_filenames,
                                       /*inout*/MemMap* reservation,
                                       /*out*/std::string* error_msg) {
   std::unique_ptr<OatFileBase> ret(new kOatFileBaseSubType(oat_location, executable));
@@ -259,7 +260,7 @@
     return nullptr;
   }
 
-  if (!ret->Setup(zip_fd, abs_dex_location, error_msg)) {
+  if (!ret->Setup(zip_fd, dex_filenames, error_msg)) {
     return nullptr;
   }
 
@@ -472,7 +473,9 @@
   return true;
 }
 
-bool OatFileBase::Setup(int zip_fd, const char* abs_dex_location, std::string* error_msg) {
+bool OatFileBase::Setup(int zip_fd,
+                        ArrayRef<const std::string> dex_filenames,
+                        std::string* error_msg) {
   if (!GetOatHeader().IsValid()) {
     std::string cause = GetOatHeader().GetValidationErrorMessage();
     *error_msg = StringPrintf("Invalid oat header for '%s': %s",
@@ -553,6 +556,9 @@
     return false;
   }
 
+  std::string_view primary_location;
+  std::string_view primary_location_replacement;
+  size_t dex_filenames_pos = 0u;
   uint32_t dex_file_count = GetOatHeader().GetDexFileCount();
   oat_dex_files_storage_.reserve(dex_file_count);
   for (size_t i = 0; i < dex_file_count; i++) {
@@ -580,19 +586,56 @@
     const char* dex_file_location_data = reinterpret_cast<const char*>(oat);
     oat += dex_file_location_size;
 
-    // Location encoded in the oat file. We will use this for multidex naming,
-    // see ResolveRelativeEncodedDexLocation.
-    std::string oat_dex_file_location(dex_file_location_data, dex_file_location_size);
-    // If `oat_dex_file_location` is relative (so that the oat file can be moved to
-    // a different folder), resolve to absolute location. Also resolve the file name
-    // in case dex files need to be opened from disk. The file name and location
-    // differ when cross-compiling on host for target.
-    std::string dex_file_name;
-    std::string dex_file_location;
-    ResolveRelativeEncodedDexLocation(abs_dex_location,
-                                      oat_dex_file_location,
-                                      &dex_file_location,
-                                      &dex_file_name);
+    // Location encoded in the oat file. We will use this for multidex naming.
+    std::string_view oat_dex_file_location(dex_file_location_data, dex_file_location_size);
+    std::string dex_file_location(oat_dex_file_location);
+    bool is_multidex = DexFileLoader::IsMultiDexLocation(dex_file_location.c_str());
+    if (!is_multidex) {
+      primary_location = oat_dex_file_location;
+      if (!dex_filenames.empty()) {
+        if (dex_filenames_pos == dex_filenames.size()) {
+          *error_msg = StringPrintf("In oat file '%s' found excessive primary location '%s'"
+                                        ", expected only %zu primary locations",
+                                    GetLocation().c_str(),
+                                    dex_file_location.c_str(),
+                                    dex_filenames.size());
+          return false;
+        }
+        primary_location_replacement = dex_filenames[dex_filenames_pos];
+        ++dex_filenames_pos;
+      }
+    }
+    if ((i == 0 && is_multidex) ||
+        (!external_dex_files_.empty() && (is_multidex != (i < external_dex_files_.size())))) {
+      *error_msg = StringPrintf("In oat file '%s' found unexpected %s location '%s'",
+                                GetLocation().c_str(),
+                                is_multidex ? "multi-dex" : "primary",
+                                dex_file_location.c_str());
+      return false;
+    }
+    if (is_multidex &&
+        (!StartsWith(dex_file_location, primary_location) ||
+             dex_file_location[primary_location.size()] != DexFileLoader::kMultiDexSeparator)) {
+      *error_msg = StringPrintf("In oat file '%s' found unexpected multidex location '%s',"
+                                    " unrelated to '%s'",
+                                GetLocation().c_str(),
+                                dex_file_location.c_str(),
+                                std::string(primary_location).c_str());
+      return false;
+    }
+    std::string dex_file_name = dex_file_location;
+    if (!dex_filenames.empty()) {
+      dex_file_name.replace(/*pos*/ 0u, primary_location.size(), primary_location_replacement);
+      // If the location does not contain path and matches the file name component,
+      // use the provided file name also as the location.
+      // TODO: Do we need this for anything other than tests?
+      if (dex_file_location.find('/') == std::string::npos &&
+          dex_file_name.size() > dex_file_location.size() &&
+          dex_file_name[dex_file_name.size() - dex_file_location.size() - 1u] == '/' &&
+          EndsWith(dex_file_name, dex_file_location)) {
+        dex_file_location = dex_file_name;
+      }
+    }
 
     uint32_t dex_file_checksum;
     if (UNLIKELY(!ReadOatDexFileData(*this, &oat, &dex_file_checksum))) {
@@ -625,17 +668,18 @@
     }
     const uint8_t* dex_file_pointer = nullptr;
     if (UNLIKELY(dex_file_offset == 0U)) {
-      if (uncompressed_dex_files_ == nullptr) {
-        // Do not support mixed-mode oat files.
-        if (i > 0) {
-          *error_msg = StringPrintf("In oat file '%s', unsupported uncompressed-dex-file for dex "
-                                        "file %zu (%s)",
-                                    GetLocation().c_str(),
-                                    i,
-                                    dex_file_location.c_str());
-          return false;
-        }
-        uncompressed_dex_files_.reset(new std::vector<std::unique_ptr<const DexFile>>());
+      // Do not support mixed-mode oat files.
+      if (i != 0u && external_dex_files_.empty()) {
+        *error_msg = StringPrintf("In oat file '%s', unsupported uncompressed-dex-file for dex "
+                                      "file %zu (%s)",
+                                  GetLocation().c_str(),
+                                  i,
+                                  dex_file_location.c_str());
+        return false;
+      }
+      DCHECK_LE(i, external_dex_files_.size());
+      if (i == external_dex_files_.size()) {
+        std::vector<std::unique_ptr<const DexFile>> new_dex_files;
         // No dex files, load it from location.
         const ArtDexFileLoader dex_file_loader;
         bool loaded = false;
@@ -645,14 +689,14 @@
                                            /*verify=*/ false,
                                            /*verify_checksum=*/ false,
                                            error_msg,
-                                           uncompressed_dex_files_.get());
+                                           &new_dex_files);
         } else {
           loaded = dex_file_loader.Open(dex_file_name.c_str(),
                                         dex_file_location,
                                         /*verify=*/ false,
                                         /*verify_checksum=*/ false,
                                         error_msg,
-                                        uncompressed_dex_files_.get());
+                                        &new_dex_files);
         }
         if (!loaded) {
           if (Runtime::Current() == nullptr) {
@@ -667,22 +711,32 @@
         }
         // The oat file may be out of date wrt/ the dex-file location. We need to be defensive
         // here and ensure that at least the number of dex files still matches.
+        // If we have a zip_fd, or reached the end of provided `dex_filenames`, we must
+        // load all dex files from that file, otherwise we may open multiple files.
         // Note: actual checksum comparisons are the duty of the OatFileAssistant and will be
         //       done after loading the OatFile.
-        if (uncompressed_dex_files_->size() != dex_file_count) {
-          *error_msg = StringPrintf("In oat file '%s', expected %u uncompressed dex files, but "
+        size_t max_dex_files = dex_file_count - external_dex_files_.size();
+        bool expect_all =
+            (zip_fd != -1) || (!dex_filenames.empty() && dex_filenames_pos == dex_filenames.size());
+        if (expect_all ? new_dex_files.size() != max_dex_files
+                       : new_dex_files.size() > max_dex_files) {
+          *error_msg = StringPrintf("In oat file '%s', expected %s%zu uncompressed dex files, but "
                                         "found %zu in '%s'",
                                     GetLocation().c_str(),
-                                    dex_file_count,
-                                    uncompressed_dex_files_->size(),
+                                    (expect_all ? "" : "<="),
+                                    max_dex_files,
+                                    new_dex_files.size(),
                                     dex_file_location.c_str());
           return false;
         }
+        for (std::unique_ptr<const DexFile>& dex_file : new_dex_files) {
+          external_dex_files_.push_back(std::move(dex_file));
+        }
       }
-      dex_file_pointer = (*uncompressed_dex_files_)[i]->Begin();
+      dex_file_pointer = external_dex_files_[i]->Begin();
     } else {
       // Do not support mixed-mode oat files.
-      if (uncompressed_dex_files_ != nullptr) {
+      if (!external_dex_files_.empty()) {
         *error_msg = StringPrintf("In oat file '%s', unsupported embedded dex-file for dex file "
                                       "%zu (%s)",
                                   GetLocation().c_str(),
@@ -837,15 +891,23 @@
     oat_dex_files_storage_.push_back(oat_dex_file);
 
     // Add the location and canonical location (if different) to the oat_dex_files_ table.
-    // Note: we use the dex_file_location_data storage for the view, as oat_dex_file_location
-    // is just a temporary string.
-    std::string_view key(dex_file_location_data, dex_file_location_size);
+    // Note: We do not add the non-canonical `dex_file_name`. If it is different from both
+    // the location and canonical location, GetOatDexFile() shall canonicalize it when
+    // requested and match the canonical path.
+    std::string_view key = oat_dex_file_location;  // References oat file data.
     std::string_view canonical_key(oat_dex_file->GetCanonicalDexFileLocation());
     oat_dex_files_.Put(key, oat_dex_file);
     if (canonical_key != key) {
       oat_dex_files_.Put(canonical_key, oat_dex_file);
     }
   }
+  if (!dex_filenames.empty() && dex_filenames_pos != dex_filenames.size()) {
+    *error_msg = StringPrintf("Oat file '%s' contains only %zu primary dex locations, expected %zu",
+                              GetLocation().c_str(),
+                              dex_filenames_pos,
+                              dex_filenames.size());
+    return false;
+  }
 
   if (DataBimgRelRoBegin() != nullptr) {
     // Make .data.bimg.rel.ro read only. ClassLinker shall temporarily make it writable for
@@ -1230,14 +1292,14 @@
                                  bool writable,
                                  bool executable,
                                  bool low_4gb,
-                                 const char* abs_dex_location,
+                                 ArrayRef<const std::string> dex_filenames,
                                  /*inout*/MemMap* reservation,  // Where to load if not null.
                                  /*out*/std::string* error_msg);
 
   bool InitializeFromElfFile(int zip_fd,
                              ElfFile* elf_file,
                              VdexFile* vdex_file,
-                             const char* abs_dex_location,
+                             ArrayRef<const std::string> dex_filenames,
                              std::string* error_msg);
 
  protected:
@@ -1291,7 +1353,7 @@
                                     bool writable,
                                     bool executable,
                                     bool low_4gb,
-                                    const char* abs_dex_location,
+                                    ArrayRef<const std::string> dex_filenames,
                                     /*inout*/MemMap* reservation,  // Where to load if not null.
                                     /*out*/std::string* error_msg) {
   ScopedTrace trace("Open elf file " + location);
@@ -1312,7 +1374,7 @@
     return nullptr;
   }
 
-  if (!oat_file->Setup(zip_fd, abs_dex_location, error_msg)) {
+  if (!oat_file->Setup(zip_fd, dex_filenames, error_msg)) {
     return nullptr;
   }
 
@@ -1322,7 +1384,7 @@
 bool ElfOatFile::InitializeFromElfFile(int zip_fd,
                                        ElfFile* elf_file,
                                        VdexFile* vdex_file,
-                                       const char* abs_dex_location,
+                                       ArrayRef<const std::string> dex_filenames,
                                        std::string* error_msg) {
   ScopedTrace trace(__PRETTY_FUNCTION__);
   if (IsExecutable()) {
@@ -1337,7 +1399,7 @@
   SetBegin(elf_file->Begin() + offset);
   SetEnd(elf_file->Begin() + size + offset);
   // Ignore the optional .bss section when opening non-executable.
-  return Setup(zip_fd, abs_dex_location, error_msg);
+  return Setup(zip_fd, dex_filenames, error_msg);
 }
 
 bool ElfOatFile::Load(const std::string& elf_filename,
@@ -1502,72 +1564,6 @@
 // General OatFile code //
 //////////////////////////
 
-static bool IsLocationSuffix(const char* abs_dex_location, const std::string& rel_dex_location) {
-  std::string_view abs_location(abs_dex_location);
-  std::string target_suffix = "/" + DexFileLoader::GetBaseLocation(rel_dex_location);
-  if (abs_location.size() <= target_suffix.size()) {
-    return false;
-  }
-  size_t pos = abs_location.size() - target_suffix.size();
-  return abs_location.compare(pos, std::string::npos, target_suffix) == 0;
-}
-
-static void MaybeResolveDexPath(const char* abs_dex_location,
-                                const std::string& rel_dex_location,
-                                bool resolve,
-                                /* out */ std::string* out_location) {
-  DCHECK(!resolve || abs_dex_location != nullptr);
-  if (out_location != nullptr) {
-    *out_location = resolve
-        ? std::string(abs_dex_location) + DexFileLoader::GetMultiDexSuffix(rel_dex_location)
-        : rel_dex_location;
-  }
-}
-
-void OatFile::ResolveRelativeEncodedDexLocation(const char* abs_dex_location,
-                                                const std::string& rel_dex_location,
-                                                /* out */ std::string* dex_file_location,
-                                                /* out */ std::string* dex_file_name) {
-  // Note that in this context `abs_dex_location` may not always be absolute
-  // and `rel_dex_location` may not always be relative. It simply means that
-  // we will try to resolve `rel_dex_location` into an absolute location using
-  // `abs_dex_location` for the base directory if needed.
-
-  bool resolve_location = false;
-  bool resolve_filename = false;
-
-  if (abs_dex_location != nullptr) {
-    if (!IsAbsoluteLocation(rel_dex_location) &&
-        IsLocationSuffix(abs_dex_location, rel_dex_location)) {
-      // The base location (w/o multidex suffix) of the relative `rel_dex_location` is a suffix
-      // of `abs_dex_location`. This typically happens for oat files which only encode the
-      // basename() so the oat and dex files can move to different directories.
-      // Example:
-      //   abs_dex_location = "/data/app/myapp/MyApplication.apk"
-      //   rel_dex_location = "MyApplication.apk!classes2.dex"
-      resolve_location = true;
-      resolve_filename = true;
-    } else {
-      // Case 1: `rel_dex_location` is absolute
-      //   On target always use `rel_dex_location` for both dex file name and dex location.
-      //   On host assume we're cross-compiling and use `abs_dex_location` as a file name
-      //   (for loading files) and `rel_dex_location` as the dex location. If we're not
-      //   cross-compiling, the two paths should be equal.
-      // Case 2: `rel_dex_location` is relative and not suffix of `abs_location`
-      //   This should never happen outside of tests. On target always use `rel_dex_location`. On
-      //   host use `abs_dex_location` with the appropriate multidex suffix because
-      //   `rel_dex_location` might be the target path.
-      resolve_location = false;
-      resolve_filename = !kIsTargetBuild;
-    }
-  }
-
-  // Construct dex file location and dex file name if the correspoding out-param pointers
-  // were provided by the caller.
-  MaybeResolveDexPath(abs_dex_location, rel_dex_location, resolve_location, dex_file_location);
-  MaybeResolveDexPath(abs_dex_location, rel_dex_location, resolve_filename, dex_file_name);
-}
-
 static void CheckLocation(const std::string& location) {
   CHECK(!location.empty());
 }
@@ -1576,10 +1572,10 @@
                                   ElfFile* elf_file,
                                   VdexFile* vdex_file,
                                   const std::string& location,
-                                  const char* abs_dex_location,
+                                  ArrayRef<const std::string> dex_filenames,
                                   std::string* error_msg) {
   std::unique_ptr<ElfOatFile> oat_file(new ElfOatFile(location, /*executable=*/ false));
-  return oat_file->InitializeFromElfFile(zip_fd, elf_file, vdex_file, abs_dex_location, error_msg)
+  return oat_file->InitializeFromElfFile(zip_fd, elf_file, vdex_file, dex_filenames, error_msg)
       ? oat_file.release()
       : nullptr;
 }
@@ -1589,7 +1585,7 @@
                        const std::string& oat_location,
                        bool executable,
                        bool low_4gb,
-                       const char* abs_dex_location,
+                       ArrayRef<const std::string> dex_filenames,
                        /*inout*/MemMap* reservation,
                        /*out*/std::string* error_msg) {
   ScopedTrace trace("Open oat file " + oat_location);
@@ -1616,7 +1612,7 @@
                                                                  /*writable=*/ false,
                                                                  executable,
                                                                  low_4gb,
-                                                                 abs_dex_location,
+                                                                 dex_filenames,
                                                                  reservation,
                                                                  error_msg);
   if (with_dlopen != nullptr) {
@@ -1645,7 +1641,7 @@
                                                                 /*writable=*/ false,
                                                                 executable,
                                                                 low_4gb,
-                                                                abs_dex_location,
+                                                                dex_filenames,
                                                                 reservation,
                                                                 error_msg);
   return with_internal;
@@ -1657,7 +1653,7 @@
                        const std::string& oat_location,
                        bool executable,
                        bool low_4gb,
-                       const char* abs_dex_location,
+                       ArrayRef<const std::string> dex_filenames,
                        /*inout*/MemMap* reservation,
                        /*out*/std::string* error_msg) {
   CHECK(!oat_location.empty()) << oat_location;
@@ -1672,7 +1668,7 @@
                                                                 /*writable=*/ false,
                                                                 executable,
                                                                 low_4gb,
-                                                                abs_dex_location,
+                                                                dex_filenames,
                                                                 reservation,
                                                                 error_msg);
   return with_internal;
@@ -1681,7 +1677,7 @@
 OatFile* OatFile::OpenWritable(int zip_fd,
                                File* file,
                                const std::string& location,
-                               const char* abs_dex_location,
+                               ArrayRef<const std::string> dex_filenames,
                                std::string* error_msg) {
   CheckLocation(location);
   return ElfOatFile::OpenElfFile(zip_fd,
@@ -1690,7 +1686,7 @@
                                  /*writable=*/ true,
                                  /*executable=*/ false,
                                  /*low_4gb=*/false,
-                                 abs_dex_location,
+                                 dex_filenames,
                                  /*reservation=*/ nullptr,
                                  error_msg);
 }
@@ -1698,7 +1694,7 @@
 OatFile* OatFile::OpenReadable(int zip_fd,
                                File* file,
                                const std::string& location,
-                               const char* abs_dex_location,
+                               ArrayRef<const std::string> dex_filenames,
                                std::string* error_msg) {
   CheckLocation(location);
   return ElfOatFile::OpenElfFile(zip_fd,
@@ -1707,7 +1703,7 @@
                                  /*writable=*/ false,
                                  /*executable=*/ false,
                                  /*low_4gb=*/false,
-                                 abs_dex_location,
+                                 dex_filenames,
                                  /*reservation=*/ nullptr,
                                  error_msg);
 }
diff --git a/runtime/oat_file.h b/runtime/oat_file.h
index 70a9534..6de07e3 100644
--- a/runtime/oat_file.h
+++ b/runtime/oat_file.h
@@ -104,20 +104,55 @@
                                   ElfFile* elf_file,
                                   VdexFile* vdex_file,
                                   const std::string& location,
-                                  const char* abs_dex_location,
+                                  ArrayRef<const std::string> dex_filenames,
                                   std::string* error_msg);
-  // Open an oat file. Returns null on failure.  Requested base can
-  // optionally be used to request where the file should be loaded.
-  // See the ResolveRelativeEncodedDexLocation for a description of how the
-  // abs_dex_location argument is used.
+  // Open an oat file. Returns null on failure.
+  // The `dex_filenames` argument, if provided, specifies dex files to
+  // open if they are not embedded in the vdex file. This may differ
+  // from dex file locations in the oat file for cross-compilation
+  // (the dex file name is the host path and dex location is the future
+  // path on target) and testing.
   static OatFile* Open(int zip_fd,
                        const std::string& filename,
                        const std::string& location,
                        bool executable,
                        bool low_4gb,
-                       const char* abs_dex_location,
+                       ArrayRef<const std::string> dex_filenames,
                        /*inout*/MemMap* reservation,  // Where to load if not null.
                        /*out*/std::string* error_msg);
+  // Helper overload that takes a single dex filename and no reservation.
+  static OatFile* Open(int zip_fd,
+                       const std::string& filename,
+                       const std::string& location,
+                       bool executable,
+                       bool low_4gb,
+                       const std::string& dex_filename,
+                       /*out*/std::string* error_msg) {
+    return Open(zip_fd,
+                filename,
+                location,
+                executable,
+                low_4gb,
+                ArrayRef<const std::string>(&dex_filename, /*size=*/ 1u),
+                /*reservation=*/ nullptr,
+                error_msg);
+  }
+  // Helper overload that takes no dex filename and no reservation.
+  static OatFile* Open(int zip_fd,
+                       const std::string& filename,
+                       const std::string& location,
+                       bool executable,
+                       bool low_4gb,
+                       /*out*/std::string* error_msg) {
+    return Open(zip_fd,
+                filename,
+                location,
+                executable,
+                low_4gb,
+                ArrayRef<const std::string>(),
+                /*reservation=*/ nullptr,
+                error_msg);
+  }
 
   // Similar to OatFile::Open(const std::string...), but accepts input vdex and
   // odex files as file descriptors. We also take zip_fd in case the vdex does not
@@ -128,7 +163,7 @@
                        const std::string& oat_location,
                        bool executable,
                        bool low_4gb,
-                       const char* abs_dex_location,
+                       ArrayRef<const std::string> dex_filenames,
                        /*inout*/MemMap* reservation,  // Where to load if not null.
                        /*out*/std::string* error_msg);
 
@@ -140,13 +175,13 @@
   static OatFile* OpenWritable(int zip_fd,
                                File* file,
                                const std::string& location,
-                               const char* abs_dex_location,
+                               ArrayRef<const std::string> dex_filenames,
                                std::string* error_msg);
   // Open an oat file from an already opened File. Maps it PROT_READ, MAP_PRIVATE.
   static OatFile* OpenReadable(int zip_fd,
                                File* file,
                                const std::string& location,
-                               const char* abs_dex_location,
+                               ArrayRef<const std::string> dex_filenames,
                                std::string* error_msg);
 
   // Initialize OatFile instance from an already loaded VdexFile. This assumes
@@ -357,28 +392,6 @@
   // Initialize relocation sections (.data.bimg.rel.ro and .bss).
   void InitializeRelocations() const;
 
-  // Constructs the absolute dex location and/or dex file name for the relative dex
-  // location (`rel_dex_location`) in the oat file, using the `abs_dex_location` of
-  // the dex file this oat belongs to.
-  //
-  // The dex file name and dex location differ when cross compiling where the dex file
-  // name is the host path (for opening files) and dex location is the future path on target.
-  //
-  // If not null, abs_dex_location is used to resolve the absolute dex
-  // location of relative dex locations encoded in the oat file.
-  // For example, given absolute location "/data/app/foo/base.apk", encoded
-  // dex locations "base.apk", "base.apk!classes2.dex", etc. would be resolved
-  // to "/data/app/foo/base.apk", "/data/app/foo/base.apk!classes2.dex", etc.
-  // Relative encoded dex locations that don't match the given abs_dex_location
-  // are left unchanged.
-  //
-  // Computation of both `dex_file_location` and `dex_file_name` can be skipped
-  // by setting the corresponding out parameter to `nullptr`.
-  static void ResolveRelativeEncodedDexLocation(const char* abs_dex_location,
-                                                const std::string& rel_dex_location,
-                                                /* out */ std::string* dex_file_location,
-                                                /* out */ std::string* dex_file_name = nullptr);
-
   // Finds the associated oat class for a dex_file and descriptor. Returns an invalid OatClass on
   // error and sets found to false.
   static OatClass FindOatClass(const DexFile& dex_file, uint16_t class_def_idx, bool* found);
@@ -389,7 +402,7 @@
 
   // Whether the OatFile embeds the Dex code.
   bool ContainsDexCode() const {
-    return uncompressed_dex_files_ == nullptr;
+    return external_dex_files_.empty();
   }
 
  protected:
@@ -470,9 +483,9 @@
   // elements. std::list<> and std::deque<> satisfy this requirement, std::vector<> doesn't.
   mutable std::list<std::string> string_cache_ GUARDED_BY(secondary_lookup_lock_);
 
-  // Cache of dex files mapped directly from a location, in case the OatFile does
-  // not embed the dex code.
-  std::unique_ptr<std::vector<std::unique_ptr<const DexFile>>> uncompressed_dex_files_;
+  // Dex files opened directly from a file referenced from the oat file or specifed
+  // by the `dex_filenames` parameter, in case the OatFile does not embed the dex code.
+  std::vector<std::unique_ptr<const DexFile>> external_dex_files_;
 
   friend class gc::collector::DummyOatFile;  // For modifying begin_ and end_.
   friend class OatClass;
diff --git a/runtime/oat_file_assistant.cc b/runtime/oat_file_assistant.cc
index 48f17f0..28984fd 100644
--- a/runtime/oat_file_assistant.cc
+++ b/runtime/oat_file_assistant.cc
@@ -843,13 +843,15 @@
       std::string error_msg;
       if (use_fd_) {
         if (oat_fd_ >= 0 && vdex_fd_ >= 0) {
+          ArrayRef<const std::string> dex_locations(&oat_file_assistant_->dex_location_,
+                                                    /*size=*/ 1u);
           file_.reset(OatFile::Open(zip_fd_,
                                     vdex_fd_,
                                     oat_fd_,
                                     filename_.c_str(),
                                     executable,
                                     /*low_4gb=*/ false,
-                                    oat_file_assistant_->dex_location_.c_str(),
+                                    dex_locations,
                                     /*reservation=*/ nullptr,
                                     &error_msg));
         }
@@ -859,8 +861,7 @@
                                   filename_.c_str(),
                                   executable,
                                   /*low_4gb=*/ false,
-                                  oat_file_assistant_->dex_location_.c_str(),
-                                  /*reservation=*/ nullptr,
+                                  oat_file_assistant_->dex_location_,
                                   &error_msg));
       }
       if (file_.get() == nullptr) {
diff --git a/runtime/oat_file_assistant_test.cc b/runtime/oat_file_assistant_test.cc
index 0412ab5..18448a7 100644
--- a/runtime/oat_file_assistant_test.cc
+++ b/runtime/oat_file_assistant_test.cc
@@ -1407,7 +1407,7 @@
       /*dex_elements=*/nullptr,
       &oat_file,
       &error_msgs);
-  EXPECT_EQ(dex_files.size(), 1u);
+  ASSERT_EQ(dex_files.size(), 1u) << android::base::Join(error_msgs, "\n");
   EXPECT_EQ(oat_file, nullptr);
   std::string stored_dex_location = dex_files[0]->GetLocation();
   {
@@ -1425,8 +1425,8 @@
       /*dex_elements=*/nullptr,
       &oat_file,
       &error_msgs);
-  EXPECT_EQ(dex_files.size(), 1u);
-  EXPECT_NE(oat_file, nullptr);
+  ASSERT_EQ(dex_files.size(), 1u) << android::base::Join(error_msgs, "\n");
+  ASSERT_NE(oat_file, nullptr);
   std::string oat_stored_dex_location = dex_files[0]->GetLocation();
   EXPECT_EQ(oat_stored_dex_location, stored_dex_location);
 }
@@ -1461,7 +1461,7 @@
       /*dex_elements=*/nullptr,
       &oat_file,
       &error_msgs);
-  EXPECT_EQ(dex_files_first.size(), 1u);
+  ASSERT_EQ(dex_files_first.size(), 1u) << android::base::Join(error_msgs, "\n");
   EXPECT_EQ(oat_file, nullptr) << dex_location;
   EXPECT_EQ(dex_files_first[0]->GetOatDexFile(), nullptr);
 
@@ -1489,8 +1489,8 @@
       /*dex_elements=*/nullptr,
       &oat_file,
       &error_msgs);
-  EXPECT_EQ(dex_files_second.size(), 1u);
-  EXPECT_NE(oat_file, nullptr);
+  ASSERT_EQ(dex_files_second.size(), 1u) << android::base::Join(error_msgs, "\n");
+  ASSERT_NE(oat_file, nullptr);
   EXPECT_NE(dex_files_second[0]->GetOatDexFile(), nullptr);
   EXPECT_NE(dex_files_second[0]->GetOatDexFile()->GetOatFile(), nullptr);
 
diff --git a/runtime/oat_file_test.cc b/runtime/oat_file_test.cc
index 7a122ba..1439442 100644
--- a/runtime/oat_file_test.cc
+++ b/runtime/oat_file_test.cc
@@ -30,107 +30,6 @@
 class OatFileTest : public DexoptTest {
 };
 
-TEST_F(OatFileTest, ResolveRelativeEncodedDexLocation_NullAbsLocation) {
-  std::string dex_location;
-  std::string dex_file_name;
-  OatFile::ResolveRelativeEncodedDexLocation(nullptr,
-                                             "/data/app/foo/base.apk",
-                                             &dex_location,
-                                             &dex_file_name);
-  ASSERT_EQ("/data/app/foo/base.apk", dex_file_name);
-  ASSERT_EQ("/data/app/foo/base.apk", dex_location);
-}
-
-TEST_F(OatFileTest, ResolveRelativeEncodedDexLocation_NullAbsLocation_Multidex) {
-  std::string dex_location;
-  std::string dex_file_name;
-  OatFile::ResolveRelativeEncodedDexLocation(nullptr,
-                                             "/data/app/foo/base.apk!classes2.dex",
-                                             &dex_location,
-                                             &dex_file_name);
-  ASSERT_EQ("/data/app/foo/base.apk!classes2.dex", dex_file_name);
-  ASSERT_EQ("/data/app/foo/base.apk!classes2.dex", dex_location);
-}
-
-TEST_F(OatFileTest, ResolveRelativeEncodedDexLocation_RelLocationAbsolute) {
-  std::string dex_location;
-  std::string dex_file_name;
-  OatFile::ResolveRelativeEncodedDexLocation("base.apk",
-                                             "/system/framework/base.apk",
-                                             &dex_location,
-                                             &dex_file_name);
-  ASSERT_EQ(kIsTargetBuild ? "/system/framework/base.apk" : "base.apk", dex_file_name);
-  ASSERT_EQ("/system/framework/base.apk", dex_location);
-}
-
-TEST_F(OatFileTest, ResolveRelativeEncodedDexLocation_BothAbsoluteLocations) {
-  std::string dex_location;
-  std::string dex_file_name;
-  OatFile::ResolveRelativeEncodedDexLocation("/data/app/foo/base.apk",
-                                             "/system/framework/base.apk",
-                                             &dex_location,
-                                             &dex_file_name);
-  ASSERT_EQ(kIsTargetBuild ? "/system/framework/base.apk" : "/data/app/foo/base.apk",
-            dex_file_name);
-  ASSERT_EQ("/system/framework/base.apk", dex_location);
-}
-
-TEST_F(OatFileTest, ResolveRelativeEncodedDexLocation_RelSuffixOfAbsLocation1) {
-  std::string dex_location;
-  std::string dex_file_name;
-  OatFile::ResolveRelativeEncodedDexLocation("/data/app/foo/base.apk",
-                                             "base.apk",
-                                             &dex_location,
-                                             &dex_file_name);
-  ASSERT_EQ("/data/app/foo/base.apk", dex_file_name);
-  ASSERT_EQ("/data/app/foo/base.apk", dex_location);
-}
-
-TEST_F(OatFileTest, ResolveRelativeEncodedDexLocation_RelSuffixOfAbsLocation2) {
-  std::string dex_location;
-  std::string dex_file_name;
-  OatFile::ResolveRelativeEncodedDexLocation("/data/app/foo/base.apk",
-                                             "foo/base.apk",
-                                             &dex_location,
-                                             &dex_file_name);
-  ASSERT_EQ("/data/app/foo/base.apk", dex_file_name);
-  ASSERT_EQ("/data/app/foo/base.apk", dex_location);
-}
-
-TEST_F(OatFileTest, ResolveRelativeEncodedDexLocation_RelSuffixOfAbsLocation_Multidex) {
-  std::string dex_location;
-  std::string dex_file_name;
-  OatFile::ResolveRelativeEncodedDexLocation("/data/app/foo/base.apk",
-                                             "base.apk!classes11.dex",
-                                             &dex_location,
-                                             &dex_file_name);
-  ASSERT_EQ("/data/app/foo/base.apk!classes11.dex", dex_file_name);
-  ASSERT_EQ("/data/app/foo/base.apk!classes11.dex", dex_location);
-}
-
-TEST_F(OatFileTest, ResolveRelativeEncodedDexLocation_RelNotSuffixOfAbsLocation1) {
-  std::string dex_location;
-  std::string dex_file_name;
-  OatFile::ResolveRelativeEncodedDexLocation("/data/app/foo/sludge.apk",
-                                             "base.apk!classes2.dex",
-                                             &dex_location,
-                                             &dex_file_name);
-  ASSERT_EQ(kIsTargetBuild ? "base.apk!classes2.dex" : "/data/app/foo/sludge.apk!classes2.dex",
-            dex_file_name);
-  ASSERT_EQ("base.apk!classes2.dex", dex_location);
-}
-
-TEST_F(OatFileTest, ResolveRelativeEncodedDexLocation_RelNotSuffixOfAbsLocation2) {
-  std::string dex_location;
-  std::string dex_file_name;
-  OatFile::ResolveRelativeEncodedDexLocation("/data/app/foo/sludge.apk",
-                                             "o/base.apk",
-                                             &dex_location,
-                                             &dex_file_name);
-  ASSERT_EQ(kIsTargetBuild ? "o/base.apk" : "/data/app/foo/sludge.apk", dex_file_name);
-  ASSERT_EQ("o/base.apk", dex_location);
-}
-
 TEST_F(OatFileTest, LoadOat) {
   std::string dex_location = GetScratchDir() + "/LoadOat.jar";
 
@@ -146,8 +45,7 @@
                                                    oat_location.c_str(),
                                                    /*executable=*/ false,
                                                    /*low_4gb=*/ false,
-                                                   dex_location.c_str(),
-                                                   /*reservation=*/ nullptr,
+                                                   dex_location,
                                                    &error_msg));
   ASSERT_TRUE(odex_file.get() != nullptr);
 
@@ -173,8 +71,7 @@
                                                      oat_location.c_str(),
                                                      /*executable=*/ false,
                                                      /*low_4gb=*/ false,
-                                                     dex_location.c_str(),
-                                                     /*reservation=*/ nullptr,
+                                                     dex_location,
                                                      &error_msg));
     ASSERT_TRUE(odex_file != nullptr);
     ASSERT_EQ(2u, odex_file->GetOatDexFiles().size());
@@ -189,8 +86,7 @@
                                                    oat_location,
                                                    /*executable=*/ false,
                                                    /*low_4gb=*/ false,
-                                                   dex_location.c_str(),
-                                                   /*reservation=*/ nullptr,
+                                                   dex_location,
                                                    &error_msg));
   EXPECT_TRUE(odex_file == nullptr);
   EXPECT_NE(std::string::npos, error_msg.find("expected 2 uncompressed dex files, but found 1"))
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index fad0de6..4b6b838 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -1227,8 +1227,6 @@
                                                     system_oat_location,
                                                     /*executable=*/ false,
                                                     /*low_4gb=*/ false,
-                                                    /*abs_dex_location=*/ nullptr,
-                                                    /*reservation=*/ nullptr,
                                                     &error_msg));
     if (oat_file == nullptr) {
       LOG(ERROR) << "Could not open boot oat file for extracting boot class path: " << error_msg;