Build dexdump2 and dexlist without libart

Finally, flesh out libdexfile enough that it can replace libart for use
in dexdump2.

Bug: 22322814
Test: make -j 50 dexdump2 dexlist
      dexdump2 -d fb/base.apk
      dexlist fb/base.apk

Change-Id: Ibf9a1cd642cd473eea0b2208d72b4768aaa17f02
diff --git a/dexdump/Android.bp b/dexdump/Android.bp
index 4916d64..eca0844 100644
--- a/dexdump/Android.bp
+++ b/dexdump/Android.bp
@@ -14,33 +14,38 @@
 
 // TODO(ajcbik): rename dexdump2 into dexdump when Dalvik version is removed
 
-art_cc_binary {
-    name: "dexdump2",
-    host_supported: true,
+
+cc_defaults {
+    name: "dexdump_defaults",
     srcs: [
         "dexdump_cfg.cc",
         "dexdump_main.cc",
         "dexdump.cc",
     ],
     cflags: ["-Wall", "-Werror"],
+    // TODO: fix b/72216369 and remove the need for this.
+    include_dirs: [
+        "art/runtime"  // dex utils.
+    ],
+}
+
+art_cc_binary {
+    name: "dexdump2",
+    defaults: ["dexdump_defaults"],
+    host_supported: true,
     shared_libs: [
-        "libart",
+        "libdexfile",
         "libbase",
     ],
 }
 
 art_cc_binary {
     name: "dexdumps",
+    defaults: ["dexdump_defaults"],
     host_supported: true,
     device_supported: false,
-    srcs: [
-        "dexdump_cfg.cc",
-        "dexdump_main.cc",
-        "dexdump.cc",
-    ],
-    cflags: ["-Wall", "-Werror"],
     static_libs: [
-        "libart",
+        "libdexfile",
         "libbase",
     ] + art_static_dependencies,
     target: {
diff --git a/dexdump/dexdump.cc b/dexdump/dexdump.cc
index 1518e1d..16cb302 100644
--- a/dexdump/dexdump.cc
+++ b/dexdump/dexdump.cc
@@ -34,8 +34,13 @@
 
 #include "dexdump.h"
 
+#include <fcntl.h>
 #include <inttypes.h>
 #include <stdio.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
 
 #include <iostream>
 #include <memory>
@@ -44,7 +49,6 @@
 
 #include "android-base/stringprintf.h"
 
-#include "dex/art_dex_file_loader.h"
 #include "dex/code_item_accessors-no_art-inl.h"
 #include "dex/dex_file-inl.h"
 #include "dex/dex_file_exception_helpers.h"
@@ -1868,6 +1872,34 @@
   }
 }
 
+static bool openAndMapFile(const char* fileName,
+                           const uint8_t** base,
+                           size_t* size,
+                           std::string* error_msg) {
+  int fd = open(fileName, O_RDONLY);
+  if (fd < 0) {
+    *error_msg = "open failed";
+    return false;
+  }
+  struct stat st;
+  if (fstat(fd, &st) < 0) {
+    *error_msg = "stat failed";
+    return false;
+  }
+  *size = st.st_size;
+  if (*size == 0) {
+    *error_msg = "size == 0";
+    return false;
+  }
+  void* addr = mmap(nullptr /*addr*/, *size, PROT_READ, MAP_PRIVATE, fd, 0 /*offset*/);
+  if (addr == MAP_FAILED) {
+    *error_msg = "mmap failed";
+    return false;
+  }
+  *base = reinterpret_cast<const uint8_t*>(addr);
+  return true;
+}
+
 /*
  * Processes a single file (either direct .dex or indirect .zip/.jar/.apk).
  */
@@ -1879,12 +1911,18 @@
   // If the file is not a .dex file, the function tries .zip/.jar/.apk files,
   // all of which are Zip archives with "classes.dex" inside.
   const bool kVerifyChecksum = !gOptions.ignoreBadChecksum;
+  const uint8_t* base = nullptr;
+  size_t size = 0;
   std::string error_msg;
-  // TODO: Use DexFileLoader when that is implemented.
-  const ArtDexFileLoader dex_file_loader;
+  if (!openAndMapFile(fileName, &base, &size, &error_msg)) {
+    fputs(error_msg.c_str(), stderr);
+    fputc('\n', stderr);
+    return -1;
+  }
+  const DexFileLoader dex_file_loader;
   std::vector<std::unique_ptr<const DexFile>> dex_files;
-  if (!dex_file_loader.Open(
-        fileName, fileName, /* verify */ true, kVerifyChecksum, &error_msg, &dex_files)) {
+  if (!dex_file_loader.OpenAll(
+        base, size, fileName, /*verify*/ true, kVerifyChecksum, &error_msg, &dex_files)) {
     // Display returned error message to user. Note that this error behavior
     // differs from the error messages shown by the original Dalvik dexdump.
     fputs(error_msg.c_str(), stderr);
diff --git a/dexdump/dexdump_main.cc b/dexdump/dexdump_main.cc
index 382b551..2247e7a 100644
--- a/dexdump/dexdump_main.cc
+++ b/dexdump/dexdump_main.cc
@@ -28,12 +28,6 @@
 #include <string.h>
 #include <unistd.h>
 
-#include <android-base/logging.h>
-
-#include <base/logging.h>  // For InitLogging.
-#include "mem_map.h"
-#include "runtime.h"
-
 namespace art {
 
 static const char* gProgName = "dexdump";
@@ -61,10 +55,6 @@
  * Main driver of the dexdump utility.
  */
 int dexdumpDriver(int argc, char** argv) {
-  // Art specific set up.
-  InitLogging(argv, Runtime::Abort);
-  MemMap::Init();
-
   // Reset options.
   bool wantUsage = false;
   memset(&gOptions, 0, sizeof(gOptions));
diff --git a/dexlist/Android.bp b/dexlist/Android.bp
index 8ecff42..2703732 100644
--- a/dexlist/Android.bp
+++ b/dexlist/Android.bp
@@ -17,7 +17,11 @@
     host_supported: true,
     srcs: ["dexlist.cc"],
     cflags: ["-Wall", "-Werror"],
-    shared_libs: ["libart", "libbase"],
+    shared_libs: ["libdexfile", "libbase"],
+    // TODO: fix b/72216369 and remove the need for this.
+    include_dirs: [
+        "art/runtime"  // dex utils.
+    ],
 }
 
 art_cc_test {
diff --git a/dexlist/dexlist.cc b/dexlist/dexlist.cc
index 1ced8ca..8daaef1 100644
--- a/dexlist/dexlist.cc
+++ b/dexlist/dexlist.cc
@@ -23,16 +23,18 @@
  * List all methods in all concrete classes in one or more DEX files.
  */
 
+#include <fcntl.h>
+#include <inttypes.h>
 #include <stdio.h>
 #include <stdlib.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
 
-#include "base/logging.h"  // For InitLogging.
-#include "dex/art_dex_file_loader.h"
 #include "dex/code_item_accessors-no_art-inl.h"
 #include "dex/dex_file-inl.h"
 #include "dex/dex_file_loader.h"
-#include "mem_map.h"
-#include "runtime.h"
 
 namespace art {
 
@@ -166,6 +168,34 @@
   }
 }
 
+static bool openAndMapFile(const char* fileName,
+                           const uint8_t** base,
+                           size_t* size,
+                           std::string* error_msg) {
+  int fd = open(fileName, O_RDONLY);
+  if (fd < 0) {
+    *error_msg = "open failed";
+    return false;
+  }
+  struct stat st;
+  if (fstat(fd, &st) < 0) {
+    *error_msg = "stat failed";
+    return false;
+  }
+  *size = st.st_size;
+  if (*size == 0) {
+    *error_msg = "size == 0";
+    return false;
+  }
+  void* addr = mmap(nullptr /*addr*/, *size, PROT_READ, MAP_PRIVATE, fd, 0 /*offset*/);
+  if (addr == MAP_FAILED) {
+    *error_msg = "mmap failed";
+    return false;
+  }
+  *base = reinterpret_cast<const uint8_t*>(addr);
+  return true;
+}
+
 /*
  * Processes a single file (either direct .dex or indirect .zip/.jar/.apk).
  */
@@ -173,11 +203,18 @@
   // If the file is not a .dex file, the function tries .zip/.jar/.apk files,
   // all of which are Zip archives with "classes.dex" inside.
   static constexpr bool kVerifyChecksum = true;
+  const uint8_t* base = nullptr;
+  size_t size = 0;
   std::string error_msg;
+  if (!openAndMapFile(fileName, &base, &size, &error_msg)) {
+    fputs(error_msg.c_str(), stderr);
+    fputc('\n', stderr);
+    return -1;
+  }
   std::vector<std::unique_ptr<const DexFile>> dex_files;
-  const ArtDexFileLoader dex_file_loader;
-  if (!dex_file_loader.Open(
-        fileName, fileName, /* verify */ true, kVerifyChecksum, &error_msg, &dex_files)) {
+  const DexFileLoader dex_file_loader;
+  if (!dex_file_loader.OpenAll(
+        base, size, fileName, /*verify*/ true, kVerifyChecksum, &error_msg, &dex_files)) {
     fputs(error_msg.c_str(), stderr);
     fputc('\n', stderr);
     return -1;
@@ -209,10 +246,6 @@
  * Main driver of the dexlist utility.
  */
 int dexlistDriver(int argc, char** argv) {
-  // Art specific set up.
-  InitLogging(argv, Runtime::Abort);
-  MemMap::Init();
-
   // Reset options.
   bool wantUsage = false;
   memset(&gOptions, 0, sizeof(gOptions));
diff --git a/runtime/Android.bp b/runtime/Android.bp
index 07764b8..ac2c625 100644
--- a/runtime/Android.bp
+++ b/runtime/Android.bp
@@ -41,12 +41,17 @@
     target: {
         android: {
             static_libs: [
+                "libziparchive",
                 "libz",
                 "libbase",
             ],
+            shared_libs: [
+                "libutils",
+            ],
         },
         host: {
             shared_libs: [
+                "libziparchive",
                 "libz",
             ],
         },
diff --git a/runtime/dex/art_dex_file_loader.h b/runtime/dex/art_dex_file_loader.h
index 8c12bf3..b31d1e9 100644
--- a/runtime/dex/art_dex_file_loader.h
+++ b/runtime/dex/art_dex_file_loader.h
@@ -68,7 +68,7 @@
                                       std::unique_ptr<MemMap> mem_map,
                                       bool verify,
                                       bool verify_checksum,
-                                      std::string* error_msg) const OVERRIDE;
+                                      std::string* error_msg) const;
 
   // Opens all .dex files found in the file, guessing the container format based on file extension.
   bool Open(const char* filename,
@@ -76,7 +76,7 @@
             bool verify,
             bool verify_checksum,
             std::string* error_msg,
-            std::vector<std::unique_ptr<const DexFile>>* dex_files) const OVERRIDE;
+            std::vector<std::unique_ptr<const DexFile>>* dex_files) const;
 
   // Open a single dex file from an fd. This function closes the fd.
   std::unique_ptr<const DexFile> OpenDex(int fd,
@@ -84,7 +84,7 @@
                                          bool verify,
                                          bool verify_checksum,
                                          bool mmap_shared,
-                                         std::string* error_msg) const OVERRIDE;
+                                         std::string* error_msg) const;
 
   // Opens dex files from within a .jar, .zip, or .apk file
   bool OpenZip(int fd,
@@ -92,7 +92,7 @@
                bool verify,
                bool verify_checksum,
                std::string* error_msg,
-               std::vector<std::unique_ptr<const DexFile>>* dex_files) const OVERRIDE;
+               std::vector<std::unique_ptr<const DexFile>>* dex_files) const;
 
  private:
   std::unique_ptr<const DexFile> OpenFile(int fd,
@@ -100,7 +100,7 @@
                                           bool verify,
                                           bool verify_checksum,
                                           bool mmap_shared,
-                                          std::string* error_msg) const OVERRIDE;
+                                          std::string* error_msg) const;
 
   // Open all classesXXX.dex files from a zip archive.
   bool OpenAllDexFilesFromZip(const ZipArchive& zip_archive,
@@ -108,8 +108,7 @@
                               bool verify,
                               bool verify_checksum,
                               std::string* error_msg,
-                              std::vector<std::unique_ptr<const DexFile>>* dex_files)
-      const OVERRIDE;
+                              std::vector<std::unique_ptr<const DexFile>>* dex_files) const;
 
   // Opens .dex file from the entry_name in a zip archive. error_code is undefined when non-null
   // return.
@@ -119,7 +118,7 @@
                                                        bool verify,
                                                        bool verify_checksum,
                                                        std::string* error_msg,
-                                                       ZipOpenErrorCode* error_code) const OVERRIDE;
+                                                       ZipOpenErrorCode* error_code) const;
 };
 
 }  // namespace art
diff --git a/runtime/dex/dex_file_loader.cc b/runtime/dex/dex_file_loader.cc
index c80ea19..ccad19f 100644
--- a/runtime/dex/dex_file_loader.cc
+++ b/runtime/dex/dex_file_loader.cc
@@ -16,25 +16,143 @@
 
 #include "dex_file_loader.h"
 
-// #include <sys/mman.h>  // For the PROT_* and MAP_* constants.
-// #include <sys/stat.h>
-
 #include "android-base/stringprintf.h"
 
-#include "base/file_magic.h"
 #include "base/stl_util.h"
-// #include "base/systrace.h"
-// #include "base/unix_file/fd_file.h"
 #include "compact_dex_file.h"
 #include "dex_file.h"
 #include "dex_file_verifier.h"
 #include "standard_dex_file.h"
-// #include "zip_archive.h"
+#include "ziparchive/zip_archive.h"
+
+// system/core/zip_archive definitions.
+struct ZipEntry;
+typedef void* ZipArchiveHandle;
 
 namespace art {
 
+namespace {
+
+class VectorContainer : public DexFileContainer {
+ public:
+  explicit VectorContainer(std::vector<uint8_t>&& vector) : vector_(std::move(vector)) { }
+  virtual ~VectorContainer() OVERRIDE { }
+
+  int GetPermissions() OVERRIDE {
+    return 0;
+  }
+
+  bool IsReadOnly() OVERRIDE {
+    return true;
+  }
+
+  bool EnableWrite() OVERRIDE {
+    return false;
+  }
+
+  bool DisableWrite() OVERRIDE {
+    return false;
+  }
+
+ private:
+  std::vector<uint8_t> vector_;
+  DISALLOW_COPY_AND_ASSIGN(VectorContainer);
+};
+
+}  // namespace
+
 using android::base::StringPrintf;
 
+class DexZipArchive;
+
+class DexZipEntry {
+ public:
+  // Extract this entry to memory.
+  // Returns null on failure and sets error_msg.
+  const std::vector<uint8_t> Extract(std::string* error_msg) {
+    std::vector<uint8_t> map(GetUncompressedLength());
+    if (map.size() == 0) {
+      DCHECK(!error_msg->empty());
+      return map;
+    }
+    const int32_t error = ExtractToMemory(handle_, zip_entry_, map.data(), map.size());
+    if (error) {
+      *error_msg = std::string(ErrorCodeString(error));
+    }
+    return map;
+  }
+
+  virtual ~DexZipEntry() {
+    delete zip_entry_;
+  }
+
+  uint32_t GetUncompressedLength() {
+    return zip_entry_->uncompressed_length;
+  }
+
+  uint32_t GetCrc32() {
+    return zip_entry_->crc32;
+  }
+
+ private:
+  DexZipEntry(ZipArchiveHandle handle,
+              ::ZipEntry* zip_entry,
+           const std::string& entry_name)
+    : handle_(handle), zip_entry_(zip_entry), entry_name_(entry_name) {}
+
+  ZipArchiveHandle handle_;
+  ::ZipEntry* const zip_entry_;
+  std::string const entry_name_;
+
+  friend class DexZipArchive;
+  DISALLOW_COPY_AND_ASSIGN(DexZipEntry);
+};
+
+class DexZipArchive {
+ public:
+  // return new DexZipArchive instance on success, null on error.
+  static DexZipArchive* Open(const uint8_t* base, size_t size, std::string* error_msg) {
+    ZipArchiveHandle handle;
+    uint8_t* nonconst_base = const_cast<uint8_t*>(base);
+    const int32_t error = OpenArchiveFromMemory(nonconst_base, size, "ZipArchiveMemory", &handle);
+    if (error) {
+      *error_msg = std::string(ErrorCodeString(error));
+      CloseArchive(handle);
+      return nullptr;
+    }
+    return new DexZipArchive(handle);
+  }
+
+  DexZipEntry* Find(const char* name, std::string* error_msg) const {
+    DCHECK(name != nullptr);
+    // Resist the urge to delete the space. <: is a bigraph sequence.
+    std::unique_ptr< ::ZipEntry> zip_entry(new ::ZipEntry);
+    const int32_t error = FindEntry(handle_, ZipString(name), zip_entry.get());
+    if (error) {
+      *error_msg = std::string(ErrorCodeString(error));
+      return nullptr;
+    }
+    return new DexZipEntry(handle_, zip_entry.release(), name);
+  }
+
+  ~DexZipArchive() {
+    CloseArchive(handle_);
+  }
+
+
+ private:
+  explicit DexZipArchive(ZipArchiveHandle handle) : handle_(handle) {}
+  ZipArchiveHandle handle_;
+
+  friend class DexZipEntry;
+  DISALLOW_COPY_AND_ASSIGN(DexZipArchive);
+};
+
+static bool IsZipMagic(uint32_t magic) {
+  return (('P' == ((magic >> 0) & 0xff)) &&
+          ('K' == ((magic >> 8) & 0xff)));
+}
+
 bool DexFileLoader::IsMagicValid(uint32_t magic) {
   return IsMagicValid(reinterpret_cast<uint8_t*>(&magic));
 }
@@ -114,80 +232,47 @@
                     /*verify_result*/ nullptr);
 }
 
-std::unique_ptr<const DexFile> DexFileLoader::Open(const std::string& location ATTRIBUTE_UNUSED,
-                                                   uint32_t location_checksum ATTRIBUTE_UNUSED,
-                                                   std::unique_ptr<MemMap> map ATTRIBUTE_UNUSED,
-                                                   bool verify ATTRIBUTE_UNUSED,
-                                                   bool verify_checksum ATTRIBUTE_UNUSED,
-                                                   std::string* error_msg) const {
-  *error_msg = "UNIMPLEMENTED";
-  return nullptr;
-}
-
-bool DexFileLoader::Open(
-    const char* filename ATTRIBUTE_UNUSED,
-    const std::string& location ATTRIBUTE_UNUSED,
-    bool verify ATTRIBUTE_UNUSED,
-    bool verify_checksum ATTRIBUTE_UNUSED,
+bool DexFileLoader::OpenAll(
+    const uint8_t* base,
+    size_t size,
+    const std::string& location,
+    bool verify,
+    bool verify_checksum,
     std::string* error_msg,
-    std::vector<std::unique_ptr<const DexFile>>* dex_files ATTRIBUTE_UNUSED) const {
-  *error_msg = "UNIMPLEMENTED";
-  return false;
-}
-
-std::unique_ptr<const DexFile> DexFileLoader::OpenDex(
-    int fd ATTRIBUTE_UNUSED,
-    const std::string& location ATTRIBUTE_UNUSED,
-    bool verify ATTRIBUTE_UNUSED,
-    bool verify_checksum ATTRIBUTE_UNUSED,
-    bool mmap_shared ATTRIBUTE_UNUSED,
-    std::string* error_msg) const {
-  *error_msg = "UNIMPLEMENTED";
-  return nullptr;
-}
-
-bool DexFileLoader::OpenZip(
-    int fd ATTRIBUTE_UNUSED,
-    const std::string& location ATTRIBUTE_UNUSED,
-    bool verify ATTRIBUTE_UNUSED,
-    bool verify_checksum ATTRIBUTE_UNUSED,
-    std::string* error_msg,
-    std::vector<std::unique_ptr<const DexFile>>* dex_files ATTRIBUTE_UNUSED) const {
-  *error_msg = "UNIMPLEMENTED";
-  return false;
-}
-
-std::unique_ptr<const DexFile> DexFileLoader::OpenFile(
-    int fd ATTRIBUTE_UNUSED,
-    const std::string& location ATTRIBUTE_UNUSED,
-    bool verify ATTRIBUTE_UNUSED,
-    bool verify_checksum ATTRIBUTE_UNUSED,
-    bool mmap_shared ATTRIBUTE_UNUSED,
-    std::string* error_msg) const {
-  *error_msg = "UNIMPLEMENTED";
-  return nullptr;
-}
-
-std::unique_ptr<const DexFile> DexFileLoader::OpenOneDexFileFromZip(
-    const ZipArchive& zip_archive ATTRIBUTE_UNUSED,
-    const char* entry_name ATTRIBUTE_UNUSED,
-    const std::string& location ATTRIBUTE_UNUSED,
-    bool verify ATTRIBUTE_UNUSED,
-    bool verify_checksum ATTRIBUTE_UNUSED,
-    std::string* error_msg,
-    ZipOpenErrorCode* error_code ATTRIBUTE_UNUSED) const {
-  *error_msg = "UNIMPLEMENTED";
-  return nullptr;
-}
-
-bool DexFileLoader::OpenAllDexFilesFromZip(
-    const ZipArchive& zip_archive ATTRIBUTE_UNUSED,
-    const std::string& location ATTRIBUTE_UNUSED,
-    bool verify ATTRIBUTE_UNUSED,
-    bool verify_checksum ATTRIBUTE_UNUSED,
-    std::string* error_msg,
-    std::vector<std::unique_ptr<const DexFile>>* dex_files ATTRIBUTE_UNUSED) const {
-  *error_msg = "UNIMPLEMENTED";
+    std::vector<std::unique_ptr<const DexFile>>* dex_files) const {
+  DCHECK(dex_files != nullptr) << "DexFile::Open: out-param is nullptr";
+  uint32_t magic = *reinterpret_cast<const uint32_t*>(base);
+  if (IsZipMagic(magic)) {
+    std::unique_ptr<DexZipArchive> zip_archive(DexZipArchive::Open(base, size, error_msg));
+    if (zip_archive.get() == nullptr) {
+      DCHECK(!error_msg->empty());
+      return false;
+    }
+    return OpenAllDexFilesFromZip(*zip_archive.get(),
+                                  location,
+                                  verify,
+                                  verify_checksum,
+                                  error_msg,
+                                  dex_files);
+  }
+  if (IsMagicValid(magic)) {
+    const DexFile::Header* dex_header = reinterpret_cast<const DexFile::Header*>(base);
+    std::unique_ptr<const DexFile> dex_file(Open(base,
+                                                 size,
+                                                 location,
+                                                 dex_header->checksum_,
+                                                 /*oat_dex_file*/ nullptr,
+                                                 verify,
+                                                 verify_checksum,
+                                                 error_msg));
+    if (dex_file.get() != nullptr) {
+      dex_files->push_back(std::move(dex_file));
+      return true;
+    } else {
+      return false;
+    }
+  }
+  *error_msg = StringPrintf("Expected valid zip or dex file");
   return false;
 }
 
@@ -238,4 +323,125 @@
   return dex_file;
 }
 
+std::unique_ptr<const DexFile> DexFileLoader::OpenOneDexFileFromZip(
+    const DexZipArchive& zip_archive,
+    const char* entry_name,
+    const std::string& location,
+    bool verify,
+    bool verify_checksum,
+    std::string* error_msg,
+    ZipOpenErrorCode* error_code) const {
+  CHECK(!location.empty());
+  std::unique_ptr<DexZipEntry> zip_entry(zip_archive.Find(entry_name, error_msg));
+  if (zip_entry == nullptr) {
+    *error_code = ZipOpenErrorCode::kEntryNotFound;
+    return nullptr;
+  }
+  if (zip_entry->GetUncompressedLength() == 0) {
+    *error_msg = StringPrintf("Dex file '%s' has zero length", location.c_str());
+    *error_code = ZipOpenErrorCode::kDexFileError;
+    return nullptr;
+  }
+
+  std::vector<uint8_t> map(zip_entry->Extract(error_msg));
+  if (map.size() == 0) {
+    *error_msg = StringPrintf("Failed to extract '%s' from '%s': %s", entry_name, location.c_str(),
+                              error_msg->c_str());
+    *error_code = ZipOpenErrorCode::kExtractToMemoryError;
+    return nullptr;
+  }
+  VerifyResult verify_result;
+  std::unique_ptr<const DexFile> dex_file = OpenCommon(map.data(),
+                                                       map.size(),
+                                                       location,
+                                                       zip_entry->GetCrc32(),
+                                                       /*oat_dex_file*/ nullptr,
+                                                       verify,
+                                                       verify_checksum,
+                                                       error_msg,
+                                                       new VectorContainer(std::move(map)),
+                                                       &verify_result);
+  if (dex_file == nullptr) {
+    if (verify_result == VerifyResult::kVerifyNotAttempted) {
+      *error_code = ZipOpenErrorCode::kDexFileError;
+    } else {
+      *error_code = ZipOpenErrorCode::kVerifyError;
+    }
+    return nullptr;
+  }
+  if (verify_result != VerifyResult::kVerifySucceeded) {
+    *error_code = ZipOpenErrorCode::kVerifyError;
+    return nullptr;
+  }
+  *error_code = ZipOpenErrorCode::kNoError;
+  return dex_file;
+}
+
+// Technically we do not have a limitation with respect to the number of dex files that can be in a
+// multidex APK. However, it's bad practice, as each dex file requires its own tables for symbols
+// (types, classes, methods, ...) and dex caches. So warn the user that we open a zip with what
+// seems an excessive number.
+static constexpr size_t kWarnOnManyDexFilesThreshold = 100;
+
+bool DexFileLoader::OpenAllDexFilesFromZip(
+    const DexZipArchive& zip_archive,
+    const std::string& location,
+    bool verify,
+    bool verify_checksum,
+    std::string* error_msg,
+    std::vector<std::unique_ptr<const DexFile>>* dex_files) const {
+  DCHECK(dex_files != nullptr) << "DexFile::OpenFromZip: out-param is nullptr";
+  ZipOpenErrorCode error_code;
+  std::unique_ptr<const DexFile> dex_file(OpenOneDexFileFromZip(zip_archive,
+                                                                kClassesDex,
+                                                                location,
+                                                                verify,
+                                                                verify_checksum,
+                                                                error_msg,
+                                                                &error_code));
+  if (dex_file.get() == nullptr) {
+    return false;
+  } else {
+    // Had at least classes.dex.
+    dex_files->push_back(std::move(dex_file));
+
+    // Now try some more.
+
+    // We could try to avoid std::string allocations by working on a char array directly. As we
+    // do not expect a lot of iterations, this seems too involved and brittle.
+
+    for (size_t i = 1; ; ++i) {
+      std::string name = GetMultiDexClassesDexName(i);
+      std::string fake_location = GetMultiDexLocation(i, location.c_str());
+      std::unique_ptr<const DexFile> next_dex_file(OpenOneDexFileFromZip(zip_archive,
+                                                                         name.c_str(),
+                                                                         fake_location,
+                                                                         verify,
+                                                                         verify_checksum,
+                                                                         error_msg,
+                                                                         &error_code));
+      if (next_dex_file.get() == nullptr) {
+        if (error_code != ZipOpenErrorCode::kEntryNotFound) {
+          LOG(WARNING) << "Zip open failed: " << *error_msg;
+        }
+        break;
+      } else {
+        dex_files->push_back(std::move(next_dex_file));
+      }
+
+      if (i == kWarnOnManyDexFilesThreshold) {
+        LOG(WARNING) << location << " has in excess of " << kWarnOnManyDexFilesThreshold
+                     << " dex files. Please consider coalescing and shrinking the number to "
+                        " avoid runtime overhead.";
+      }
+
+      if (i == std::numeric_limits<size_t>::max()) {
+        LOG(ERROR) << "Overflow in number of dex files!";
+        break;
+      }
+    }
+
+    return true;
+  }
+}
 }  // namespace art
diff --git a/runtime/dex/dex_file_loader.h b/runtime/dex/dex_file_loader.h
index 4e45fb0..05a51d0 100644
--- a/runtime/dex/dex_file_loader.h
+++ b/runtime/dex/dex_file_loader.h
@@ -28,7 +28,8 @@
 class DexFileContainer;
 class MemMap;
 class OatDexFile;
-class ZipArchive;
+
+class DexZipArchive;
 
 // Class that is used to open dex files and deal with corresponding multidex and location logic.
 class DexFileLoader {
@@ -46,68 +47,10 @@
   // Return true if the corresponding version and magic is valid.
   static bool IsVersionAndMagicValid(const uint8_t* magic);
 
-  virtual ~DexFileLoader() { }
-
-  // Returns the checksums of a file for comparison with GetLocationChecksum().
-  // For .dex files, this is the single header checksum.
-  // For zip files, this is the zip entry CRC32 checksum for classes.dex and
-  // each additional multidex entry classes2.dex, classes3.dex, etc.
-  // If a valid zip_fd is provided the file content will be read directly from
-  // the descriptor and `filename` will be used as alias for error logging. If
-  // zip_fd is -1, the method will try to open the `filename` and read the
-  // content from it.
-  // Return true if the checksums could be found, false otherwise.
-  virtual bool GetMultiDexChecksums(const char* filename,
-                                    std::vector<uint32_t>* checksums,
-                                    std::string* error_msg,
-                                    int zip_fd = -1) const;
-
   // Check whether a location denotes a multidex dex file. This is a very simple check: returns
   // whether the string contains the separator character.
   static bool IsMultiDexLocation(const char* location);
 
-  // Opens .dex file, backed by existing memory
-  virtual std::unique_ptr<const DexFile> Open(const uint8_t* base,
-                                              size_t size,
-                                              const std::string& location,
-                                              uint32_t location_checksum,
-                                              const OatDexFile* oat_dex_file,
-                                              bool verify,
-                                              bool verify_checksum,
-                                              std::string* error_msg) const;
-
-  // Opens .dex file that has been memory-mapped by the caller.
-  virtual std::unique_ptr<const DexFile> Open(const std::string& location,
-                                              uint32_t location_checkum,
-                                              std::unique_ptr<MemMap> mem_map,
-                                              bool verify,
-                                              bool verify_checksum,
-                                              std::string* error_msg) const;
-
-  // Opens all .dex files found in the file, guessing the container format based on file extension.
-  virtual bool Open(const char* filename,
-                    const std::string& location,
-                    bool verify,
-                    bool verify_checksum,
-                    std::string* error_msg,
-                    std::vector<std::unique_ptr<const DexFile>>* dex_files) const;
-
-  // Open a single dex file from an fd. This function closes the fd.
-  virtual std::unique_ptr<const DexFile> OpenDex(int fd,
-                                                 const std::string& location,
-                                                 bool verify,
-                                                 bool verify_checksum,
-                                                 bool mmap_shared,
-                                                 std::string* error_msg) const;
-
-  // Opens dex files from within a .jar, .zip, or .apk file
-  virtual bool OpenZip(int fd,
-                       const std::string& location,
-                       bool verify,
-                       bool verify_checksum,
-                       std::string* error_msg,
-                       std::vector<std::unique_ptr<const DexFile>>* dex_files) const;
-
   // Return the name of the index-th classes.dex in a multidex zip file. This is classes.dex for
   // index == 0, and classes{index + 1}.dex else.
   static std::string GetMultiDexClassesDexName(size_t index);
@@ -151,6 +94,42 @@
     return (pos == std::string::npos) ? std::string() : location.substr(pos);
   }
 
+  virtual ~DexFileLoader() { }
+
+  // Returns the checksums of a file for comparison with GetLocationChecksum().
+  // For .dex files, this is the single header checksum.
+  // For zip files, this is the zip entry CRC32 checksum for classes.dex and
+  // each additional multidex entry classes2.dex, classes3.dex, etc.
+  // If a valid zip_fd is provided the file content will be read directly from
+  // the descriptor and `filename` will be used as alias for error logging. If
+  // zip_fd is -1, the method will try to open the `filename` and read the
+  // content from it.
+  // Return true if the checksums could be found, false otherwise.
+  virtual bool GetMultiDexChecksums(const char* filename,
+                                    std::vector<uint32_t>* checksums,
+                                    std::string* error_msg,
+                                    int zip_fd = -1) const;
+
+  // Opens .dex file, backed by existing memory
+  virtual std::unique_ptr<const DexFile> Open(const uint8_t* base,
+                                              size_t size,
+                                              const std::string& location,
+                                              uint32_t location_checksum,
+                                              const OatDexFile* oat_dex_file,
+                                              bool verify,
+                                              bool verify_checksum,
+                                              std::string* error_msg) const;
+
+  // Opens all .dex files found in the memory map, guessing the container format based on file
+  // extension.
+  virtual bool OpenAll(const uint8_t* base,
+                       size_t size,
+                       const std::string& location,
+                       bool verify,
+                       bool verify_checksum,
+                       std::string* error_msg,
+                       std::vector<std::unique_ptr<const DexFile>>* dex_files) const;
+
  protected:
   enum class ZipOpenErrorCode {
     kNoError,
@@ -179,30 +158,23 @@
                                              VerifyResult* verify_result);
 
  private:
-  virtual std::unique_ptr<const DexFile> OpenFile(int fd,
-                                                  const std::string& location,
-                                                  bool verify,
-                                                  bool verify_checksum,
-                                                  bool mmap_shared,
-                                                  std::string* error_msg) const;
-
   // Open all classesXXX.dex files from a zip archive.
-  virtual bool OpenAllDexFilesFromZip(const ZipArchive& zip_archive,
-                                      const std::string& location,
-                                      bool verify,
-                                      bool verify_checksum,
-                                      std::string* error_msg,
-                                      std::vector<std::unique_ptr<const DexFile>>* dex_files) const;
+  bool OpenAllDexFilesFromZip(const DexZipArchive& zip_archive,
+                              const std::string& location,
+                              bool verify,
+                              bool verify_checksum,
+                              std::string* error_msg,
+                              std::vector<std::unique_ptr<const DexFile>>* dex_files) const;
 
   // Opens .dex file from the entry_name in a zip archive. error_code is undefined when non-null
   // return.
-  virtual std::unique_ptr<const DexFile> OpenOneDexFileFromZip(const ZipArchive& zip_archive,
-                                                               const char* entry_name,
-                                                               const std::string& location,
-                                                               bool verify,
-                                                               bool verify_checksum,
-                                                               std::string* error_msg,
-                                                               ZipOpenErrorCode* error_code) const;
+  std::unique_ptr<const DexFile> OpenOneDexFileFromZip(const DexZipArchive& zip_archive,
+                                                       const char* entry_name,
+                                                       const std::string& location,
+                                                       bool verify,
+                                                       bool verify_checksum,
+                                                       std::string* error_msg,
+                                                       ZipOpenErrorCode* error_code) const;
 };
 
 }  // namespace art