Simplify libdexfile external api.

Bug: 123517037
Test: m test-art-host-gtest
Test: libunwindstack_unit_test
Test: simpleperf_unit_test --gtest_filter=*dex*
Change-Id: I1bd9a6849ad79d9ddd0a0dfb93ea7c7d2311bf49
diff --git a/libdexfile/Android.bp b/libdexfile/Android.bp
index 63f2827..8aa287f 100644
--- a/libdexfile/Android.bp
+++ b/libdexfile/Android.bp
@@ -395,7 +395,10 @@
         "external/dex_file_supp.cc",
     ],
     runtime_libs: ["libdexfile_external"],
-    shared_libs: ["liblog"],
+    shared_libs: [
+        "liblog",
+        "libbase",
+    ],
     header_libs: ["libdexfile_external_headers"],
     export_header_lib_headers: ["libdexfile_external_headers"],
 
diff --git a/libdexfile/external/dex_file_ext.cc b/libdexfile/external/dex_file_ext.cc
index c574ff3..65c0920 100644
--- a/libdexfile/external/dex_file_ext.cc
+++ b/libdexfile/external/dex_file_ext.cc
@@ -42,74 +42,29 @@
 #include <dex/dex_file-inl.h>
 #include <dex/dex_file_loader.h>
 
-namespace art {
-namespace {
-
-struct MethodCacheEntry {
-  int32_t offset;  // Offset relative to the start of the dex file header.
-  int32_t len;
-  int32_t index;  // Method index.
-};
-
-class MappedFileContainer : public DexFileContainer {
- public:
-  explicit MappedFileContainer(std::unique_ptr<android::base::MappedFile>&& map)
-      : map_(std::move(map)) {}
-  ~MappedFileContainer() override {}
-  int GetPermissions() override { return 0; }
-  bool IsReadOnly() override { return true; }
-  bool EnableWrite() override { return false; }
-  bool DisableWrite() override { return false; }
-
- private:
-  std::unique_ptr<android::base::MappedFile> map_;
-  DISALLOW_COPY_AND_ASSIGN(MappedFileContainer);
-};
-
-}  // namespace
-}  // namespace art
-
 extern "C" {
-
-struct ExtDexFileString {
-  const std::string str_;
-};
-
-static const ExtDexFileString empty_string{""};
-
-const ExtDexFileString* ExtDexFileMakeString(const char* str, size_t size) {
-  if (size == 0) {
-    return &empty_string;
-  }
-  return new ExtDexFileString{std::string(str, size)};
-}
-
-const char* ExtDexFileGetString(const ExtDexFileString* ext_string, /*out*/ size_t* size) {
-  DCHECK(ext_string != nullptr);
-  *size = ext_string->str_.size();
-  return ext_string->str_.data();
-}
-
-void ExtDexFileFreeString(const ExtDexFileString* ext_string) {
-  DCHECK(ext_string != nullptr);
-  if (ext_string != &empty_string) {
-    delete (ext_string);
-  }
-}
-
 // Wraps DexFile to add the caching needed by the external interface. This is
 // what gets passed over as ExtDexFile*.
 struct ExtDexFile {
+  struct MethodCacheEntry {
+    uint32_t offset;  // Offset relative to the start of the dex file header.
+    uint32_t len;
+    uint32_t index;  // Method index.
+  };
+
  public:
   std::unique_ptr<const art::DexFile> dex_file_;
   explicit ExtDexFile(std::unique_ptr<const art::DexFile>&& dex_file)
       : dex_file_(std::move(dex_file)) {}
 
-  art::MethodCacheEntry* GetMethodCacheEntryForOffset(int64_t dex_offset) {
+  bool GetMethodDefIndex(uint32_t dex_offset, uint32_t* index, uint32_t* addr, uint32_t* size) {
     // First look in the method cache.
     auto it = method_cache_.upper_bound(dex_offset);
     if (it != method_cache_.end() && dex_offset >= it->second.offset) {
-      return &it->second;
+      *index = it->second.index;
+      *addr = it->second.offset;
+      *size = it->second.len;
+      return true;
     }
 
     uint32_t class_def_index;
@@ -122,17 +77,18 @@
           continue;
         }
 
-        int32_t offset = reinterpret_cast<const uint8_t*>(code.Insns()) - dex_file_->Begin();
-        int32_t len = code.InsnsSizeInBytes();
+        uint32_t offset = reinterpret_cast<const uint8_t*>(code.Insns()) - dex_file_->Begin();
+        uint32_t len = code.InsnsSizeInBytes();
         if (offset <= dex_offset && dex_offset < offset + len) {
-          int32_t index = method.GetIndex();
-          auto res = method_cache_.emplace(offset + len, art::MethodCacheEntry{offset, len, index});
-          return &res.first->second;
+          *index = method.GetIndex();
+          *addr = offset;
+          *size = len;
+          method_cache_.emplace(offset + len, MethodCacheEntry{offset, len, *index});
+          return true;
         }
       }
     }
-
-    return nullptr;
+    return false;
   }
 
  private:
@@ -183,18 +139,16 @@
 
   // Binary search table with (end_dex_offset, class_def_index) entries.
   std::vector<std::pair<uint32_t, uint32_t>> class_cache_;
-  std::map<uint32_t, art::MethodCacheEntry> method_cache_;  // end_dex_offset -> method.
+  std::map<uint32_t, MethodCacheEntry> method_cache_;  // end_dex_offset -> method.
 };
 
 int ExtDexFileOpenFromMemory(const void* addr,
                              /*inout*/ size_t* size,
                              const char* location,
-                             /*out*/ const ExtDexFileString** ext_error_msg,
                              /*out*/ ExtDexFile** ext_dex_file) {
   if (*size < sizeof(art::DexFile::Header)) {
     *size = sizeof(art::DexFile::Header);
-    *ext_error_msg = nullptr;
-    return false;
+    return kExtDexFileNotEnoughData;
   }
 
   const art::DexFile::Header* header = reinterpret_cast<const art::DexFile::Header*>(addr);
@@ -206,23 +160,18 @@
     //       In practice, this should be fine, as such sharing only happens on disk.
     uint32_t computed_file_size;
     if (__builtin_add_overflow(header->data_off_, header->data_size_, &computed_file_size)) {
-      *ext_error_msg = new ExtDexFileString{
-          android::base::StringPrintf("Corrupt CompactDexFile header in '%s'", location)};
-      return false;
+      return kExtDexFileInvalidHeader;
     }
     if (computed_file_size > file_size) {
       file_size = computed_file_size;
     }
   } else if (!art::StandardDexFile::IsMagicValid(header->magic_)) {
-    *ext_error_msg = new ExtDexFileString{
-        android::base::StringPrintf("Unrecognized dex file header in '%s'", location)};
-    return false;
+    return kExtDexFileInvalidHeader;
   }
 
   if (*size < file_size) {
     *size = file_size;
-    *ext_error_msg = nullptr;
-    return false;
+    return kExtDexFileNotEnoughData;
   }
 
   std::string loc_str(location);
@@ -237,99 +186,19 @@
                                                              /*verify_checksum=*/false,
                                                              &error_msg);
   if (dex_file == nullptr) {
-    *ext_error_msg = new ExtDexFileString{std::move(error_msg)};
-    return false;
+    LOG(ERROR) << "Can not opend dex file " << loc_str << ": " << error_msg;
+    return kExtDexFileError;
   }
 
   *ext_dex_file = new ExtDexFile(std::move(dex_file));
-  return true;
-}
-
-int ExtDexFileOpenFromFd(int fd,
-                         off_t offset,
-                         const char* location,
-                         /*out*/ const ExtDexFileString** ext_error_msg,
-                         /*out*/ ExtDexFile** ext_dex_file) {
-  size_t length;
-  {
-    struct stat sbuf;
-    std::memset(&sbuf, 0, sizeof(sbuf));
-    if (fstat(fd, &sbuf) == -1) {
-      *ext_error_msg = new ExtDexFileString{
-          android::base::StringPrintf("fstat '%s' failed: %s", location, std::strerror(errno))};
-      return false;
-    }
-    if (S_ISDIR(sbuf.st_mode)) {
-      *ext_error_msg = new ExtDexFileString{
-          android::base::StringPrintf("Attempt to mmap directory '%s'", location)};
-      return false;
-    }
-    length = sbuf.st_size;
-  }
-
-  if (length < offset + sizeof(art::DexFile::Header)) {
-    *ext_error_msg = new ExtDexFileString{android::base::StringPrintf(
-        "Offset %" PRId64 " too large for '%s' of size %zu",
-        int64_t{offset},
-        location,
-        length)};
-    return false;
-  }
-
-  // Cannot use MemMap in libartbase here, because it pulls in dlopen which we
-  // can't have when being compiled statically.
-  std::unique_ptr<android::base::MappedFile> map =
-      android::base::MappedFile::FromFd(fd, offset, length, PROT_READ);
-  if (map == nullptr) {
-    *ext_error_msg = new ExtDexFileString{
-        android::base::StringPrintf("mmap '%s' failed: %s", location, std::strerror(errno))};
-    return false;
-  }
-
-  const art::DexFile::Header* header = reinterpret_cast<const art::DexFile::Header*>(map->data());
-  uint32_t file_size;
-  if (__builtin_add_overflow(offset, header->file_size_, &file_size)) {
-    *ext_error_msg =
-        new ExtDexFileString{android::base::StringPrintf("Corrupt header in '%s'", location)};
-    return false;
-  }
-  if (length < file_size) {
-    *ext_error_msg = new ExtDexFileString{
-        android::base::StringPrintf("Dex file '%s' too short: expected %" PRIu32 ", got %" PRIu64,
-                                    location,
-                                    file_size,
-                                    uint64_t{length})};
-    return false;
-  }
-
-  void* addr = map->data();
-  size_t size = map->size();
-  auto container = std::make_unique<art::MappedFileContainer>(std::move(map));
-
-  std::string loc_str(location);
-  std::string error_msg;
-  art::DexFileLoader loader;
-  std::unique_ptr<const art::DexFile> dex_file = loader.Open(reinterpret_cast<const uint8_t*>(addr),
-                                                             size,
-                                                             loc_str,
-                                                             header->checksum_,
-                                                             /*oat_dex_file=*/nullptr,
-                                                             /*verify=*/false,
-                                                             /*verify_checksum=*/false,
-                                                             &error_msg,
-                                                             std::move(container));
-  if (dex_file == nullptr) {
-    *ext_error_msg = new ExtDexFileString{std::move(error_msg)};
-    return false;
-  }
-  *ext_dex_file = new ExtDexFile(std::move(dex_file));
-  return true;
+  return kExtDexFileOk;
 }
 
 int ExtDexFileGetMethodInfoForOffset(ExtDexFile* ext_dex_file,
-                                     int64_t dex_offset,
-                                     int with_signature,
-                                     /*out*/ ExtDexFileMethodInfo* method_info) {
+                                     uint32_t dex_offset,
+                                     uint32_t flags,
+                                     ExtDexFileMethodInfoCallback* method_info_cb,
+                                     void* user_data) {
   if (!ext_dex_file->dex_file_->IsInDataSection(ext_dex_file->dex_file_->Begin() + dex_offset)) {
     return false;  // The DEX offset is not within the bytecode of this dex file.
   }
@@ -346,40 +215,49 @@
     }
   }
 
-  art::MethodCacheEntry* entry = ext_dex_file->GetMethodCacheEntryForOffset(dex_offset);
-  if (entry != nullptr) {
-    method_info->offset = entry->offset;
-    method_info->len = entry->len;
-    method_info->name =
-        new ExtDexFileString{ext_dex_file->dex_file_->PrettyMethod(entry->index, with_signature)};
-    return true;
+  uint32_t method_index, addr, size;
+  if (!ext_dex_file->GetMethodDefIndex(dex_offset, &method_index, &addr, &size)) {
+    return false;
   }
 
-  return false;
+  bool with_signature = flags & kExtDexFileWithSignature;
+  std::string name = ext_dex_file->dex_file_->PrettyMethod(method_index, with_signature);
+  ExtDexFileMethodInfo info {
+    .sizeof_struct = sizeof(ExtDexFileMethodInfo),
+    .addr = addr,
+    .size = size,
+    .name = name.c_str(),
+    .name_size = name.size()
+  };
+  method_info_cb(user_data, &info);
+  return true;
 }
 
 void ExtDexFileGetAllMethodInfos(ExtDexFile* ext_dex_file,
-                                 int with_signature,
+                                 uint32_t flags,
                                  ExtDexFileMethodInfoCallback* method_info_cb,
                                  void* user_data) {
+  const art::DexFile* dex_file = ext_dex_file->dex_file_.get();
   for (art::ClassAccessor accessor : ext_dex_file->dex_file_->GetClasses()) {
     for (const art::ClassAccessor::Method& method : accessor.GetMethods()) {
       art::CodeItemInstructionAccessor code = method.GetInstructions();
-      if (!code.HasCodeItem()) {
-        continue;
+      if (code.HasCodeItem()) {
+        const uint8_t* insns = reinterpret_cast<const uint8_t*>(code.Insns());
+        bool with_signature = flags & kExtDexFileWithSignature;
+        std::string name = dex_file->PrettyMethod(method.GetIndex(), with_signature);
+        ExtDexFileMethodInfo info {
+          .sizeof_struct = sizeof(ExtDexFileMethodInfo),
+          .addr = static_cast<uint32_t>(insns - dex_file->Begin()),
+          .size = code.InsnsSizeInBytes(),
+          .name = name.c_str(),
+          .name_size = name.size()
+        };
+        method_info_cb(user_data, &info);
       }
-
-      ExtDexFileMethodInfo method_info;
-      method_info.offset = static_cast<int32_t>(reinterpret_cast<const uint8_t*>(code.Insns()) -
-                                                ext_dex_file->dex_file_->Begin());
-      method_info.len = code.InsnsSizeInBytes();
-      method_info.name = new ExtDexFileString{
-          ext_dex_file->dex_file_->PrettyMethod(method.GetIndex(), with_signature)};
-      method_info_cb(&method_info, user_data);
     }
   }
 }
 
-void ExtDexFileFree(ExtDexFile* ext_dex_file) { delete (ext_dex_file); }
+void ExtDexFileClose(ExtDexFile* ext_dex_file) { delete (ext_dex_file); }
 
 }  // extern "C"
diff --git a/libdexfile/external/dex_file_supp.cc b/libdexfile/external/dex_file_supp.cc
index c0bfe54..7200451 100644
--- a/libdexfile/external/dex_file_supp.cc
+++ b/libdexfile/external/dex_file_supp.cc
@@ -17,7 +17,12 @@
 #include "art_api/dex_file_support.h"
 
 #include <dlfcn.h>
+#include <inttypes.h>
 #include <mutex>
+#include <sys/stat.h>
+
+#include <android-base/mapped_file.h>
+#include <android-base/stringprintf.h>
 
 #ifndef STATIC_LIB
 // Not used in the static lib, so avoid a dependency on this header in
@@ -29,14 +34,10 @@
 namespace dex {
 
 #define FOR_ALL_DLFUNCS(MACRO) \
-  MACRO(DexString, ExtDexFileMakeString) \
-  MACRO(DexString, ExtDexFileGetString) \
-  MACRO(DexString, ExtDexFileFreeString) \
   MACRO(DexFile, ExtDexFileOpenFromMemory) \
-  MACRO(DexFile, ExtDexFileOpenFromFd) \
   MACRO(DexFile, ExtDexFileGetMethodInfoForOffset) \
   MACRO(DexFile, ExtDexFileGetAllMethodInfos) \
-  MACRO(DexFile, ExtDexFileFree)
+  MACRO(DexFile, ExtDexFileClose)
 
 #ifdef STATIC_LIB
 #define DEFINE_DLFUNC_PTR(CLASS, DLFUNC) decltype(DLFUNC)* CLASS::g_##DLFUNC = DLFUNC;
@@ -103,15 +104,97 @@
 #endif
 }
 
-DexFile::~DexFile() { g_ExtDexFileFree(ext_dex_file_); }
+DexFile::~DexFile() { g_ExtDexFileClose(ext_dex_file_); }
 
-MethodInfo DexFile::AbsorbMethodInfo(const ExtDexFileMethodInfo& ext_method_info) {
-  return {ext_method_info.offset, ext_method_info.len, DexString(ext_method_info.name)};
+std::unique_ptr<DexFile> DexFile::OpenFromMemory(const void* addr,
+                                                 size_t* size,
+                                                 const std::string& location,
+                                                 /*out*/ std::string* error_msg) {
+  if (UNLIKELY(g_ExtDexFileOpenFromMemory == nullptr)) {
+    // Load libdexfile_external.so in this factory function, so instance
+    // methods don't need to check this.
+    LoadLibdexfileExternal();
+  }
+  ExtDexFile* ext_dex_file;
+  int res = g_ExtDexFileOpenFromMemory(addr, size, location.c_str(), &ext_dex_file);
+  switch (static_cast<ExtDexFileError>(res)) {
+    case kExtDexFileOk:
+      return std::unique_ptr<DexFile>(new DexFile(ext_dex_file));
+    case kExtDexFileInvalidHeader:
+      *error_msg = std::string("Invalid DexFile header ") + location;
+      return nullptr;
+    case kExtDexFileNotEnoughData:
+      *error_msg = std::string("Not enough data");
+      return nullptr;
+    case kExtDexFileError:
+      break;
+  }
+  *error_msg = std::string("Failed to open DexFile ") + location;
+  return nullptr;
 }
 
-void DexFile::AddMethodInfoCallback(const ExtDexFileMethodInfo* ext_method_info, void* ctx) {
-  auto vect = static_cast<MethodInfoVector*>(ctx);
-  vect->emplace_back(AbsorbMethodInfo(*ext_method_info));
+std::unique_ptr<DexFile> DexFile::OpenFromFd(int fd,
+                                             off_t offset,
+                                             const std::string& location,
+                                             /*out*/ std::string* error_msg) {
+  using android::base::StringPrintf;
+  size_t length;
+  {
+    struct stat sbuf;
+    std::memset(&sbuf, 0, sizeof(sbuf));
+    if (fstat(fd, &sbuf) == -1) {
+      *error_msg = StringPrintf("fstat '%s' failed: %s", location.c_str(), std::strerror(errno));
+      return nullptr;
+    }
+    if (S_ISDIR(sbuf.st_mode)) {
+      *error_msg = StringPrintf("Attempt to mmap directory '%s'", location.c_str());
+      return nullptr;
+    }
+    length = sbuf.st_size;
+  }
+
+  if (static_cast<off_t>(length) < offset) {
+    *error_msg = StringPrintf(
+        "Offset %" PRId64 " too large for '%s' of size %zu",
+        int64_t{offset},
+        location.c_str(),
+        length);
+    return nullptr;
+  }
+  length -= offset;
+
+  std::unique_ptr<android::base::MappedFile> map;
+  map = android::base::MappedFile::FromFd(fd, offset, length, PROT_READ);
+  if (map == nullptr) {
+    *error_msg = StringPrintf("mmap '%s' failed: %s", location.c_str(), std::strerror(errno));
+    return nullptr;
+  }
+
+  std::unique_ptr<DexFile> dex = OpenFromMemory(map->data(), &length, location, error_msg);
+  if (dex != nullptr) {
+    dex->map_ = std::move(map);  // Ensure the map gets freed with the dex file.
+  }
+  return dex;
+}
+
+MethodInfo DexFile::GetMethodInfoForOffset(int64_t dex_offset, bool with_signature) {
+  MethodInfo res{};
+  auto set_method = [](void* ctx, ExtDexFileMethodInfo* info) {
+    *reinterpret_cast<MethodInfo*>(ctx) = AbsorbMethodInfo(info);
+  };
+  uint32_t flags = with_signature ? kExtDexFileWithSignature : 0;
+  g_ExtDexFileGetMethodInfoForOffset(ext_dex_file_, dex_offset, flags, set_method, &res);
+  return res;
+}
+
+std::vector<MethodInfo> DexFile::GetAllMethodInfos(bool with_signature) {
+  std::vector<MethodInfo> res;
+  auto add_method = [](void* ctx, ExtDexFileMethodInfo* info) {
+    reinterpret_cast<std::vector<MethodInfo>*>(ctx)->push_back(AbsorbMethodInfo(info));
+  };
+  uint32_t flags = with_signature ? kExtDexFileWithSignature : 0;
+  g_ExtDexFileGetAllMethodInfos(ext_dex_file_, flags, add_method, &res);
+  return res;
 }
 
 }  // namespace dex
diff --git a/libdexfile/external/dex_file_supp_test.cc b/libdexfile/external/dex_file_supp_test.cc
index 0d7644a..ff263fc 100644
--- a/libdexfile/external/dex_file_supp_test.cc
+++ b/libdexfile/external/dex_file_supp_test.cc
@@ -49,69 +49,12 @@
     0x00000002, 0x00000173, 0x00002000, 0x00000001, 0x0000017e, 0x00001000, 0x00000001, 0x0000018c,
 };
 
-TEST(DexStringTest, alloc_string) {
-  auto s = DexString("123");
-  EXPECT_EQ(std::string_view(s), "123");
-}
-
-TEST(DexStringTest, alloc_empty_string) {
-  auto s = DexString("");
-  EXPECT_TRUE(std::string_view(s).empty());
-}
-
-TEST(DexStringTest, move_construct) {
-  auto s1 = DexString("foo");
-  auto s2 = DexString(std::move(s1));
-  EXPECT_TRUE(std::string_view(s1).empty()); // NOLINT bugprone-use-after-move
-  EXPECT_EQ(std::string_view(s2), "foo");
-}
-
-TEST(DexStringTest, move_assign) {
-  auto s1 = DexString("foo");
-  DexString s2;
-  EXPECT_TRUE(std::string_view(s2).empty());
-  s2 = std::move(s1);
-  EXPECT_TRUE(std::string_view(s1).empty()); // NOLINT bugprone-use-after-move
-  EXPECT_EQ(std::string_view(s2), "foo");
-}
-
-TEST(DexStringTest, reassign) {
-  auto s = DexString("foo");
-  s = DexString("bar");
-  EXPECT_EQ(std::string_view(s), "bar");
-}
-
-TEST(DexStringTest, data_access) {
-  auto s = DexString("foo");
-  EXPECT_STREQ(s.data(), "foo");
-  EXPECT_STREQ(s.c_str(), "foo");
-}
-
-TEST(DexStringTest, size_access) {
-  auto s = DexString("foo");
-  EXPECT_EQ(s.size(), size_t{3});
-  EXPECT_EQ(s.length(), size_t{3});
-}
-
-TEST(DexStringTest, equality) {
-  auto s = DexString("foo");
-  EXPECT_EQ(s, DexString("foo"));
-  EXPECT_FALSE(s == DexString("bar"));
-}
-
-TEST(DexStringTest, equality_with_nul) {
-  auto s = DexString(std::string("foo\0bar", 7));
-  EXPECT_EQ(s.size(), size_t{7});
-  EXPECT_EQ(s, DexString(std::string("foo\0bar", 7)));
-  EXPECT_FALSE(s == DexString(std::string("foo\0baz", 7)));
-}
-
 TEST(DexFileTest, from_memory_header_too_small) {
   size_t size = sizeof(art::DexFile::Header) - 1;
   std::string error_msg;
   EXPECT_EQ(DexFile::OpenFromMemory(kDexData, &size, "", &error_msg), nullptr);
   EXPECT_EQ(size, sizeof(art::DexFile::Header));
-  EXPECT_TRUE(error_msg.empty());
+  EXPECT_FALSE(error_msg.empty());
 }
 
 TEST(DexFileTest, from_memory_file_too_small) {
@@ -119,7 +62,7 @@
   std::string error_msg;
   EXPECT_EQ(DexFile::OpenFromMemory(kDexData, &size, "", &error_msg), nullptr);
   EXPECT_EQ(size, sizeof(kDexData));
-  EXPECT_TRUE(error_msg.empty());
+  EXPECT_FALSE(error_msg.empty());
 }
 
 static std::unique_ptr<DexFile> GetTestDexData() {
@@ -259,8 +202,8 @@
   ASSERT_NE(dex_file, nullptr);
 
   std::vector<MethodInfo> infos;
-  infos.emplace_back(MethodInfo{0x100, 8, DexString("Main.<init>")});
-  infos.emplace_back(MethodInfo{0x118, 2, DexString("Main.main")});
+  infos.emplace_back(MethodInfo{0x100, 8, std::string("Main.<init>")});
+  infos.emplace_back(MethodInfo{0x118, 2, std::string("Main.main")});
   ASSERT_EQ(dex_file->GetAllMethodInfos(false), infos);
 }
 
@@ -269,8 +212,8 @@
   ASSERT_NE(dex_file, nullptr);
 
   std::vector<MethodInfo> infos;
-  infos.emplace_back(MethodInfo{0x100, 8, DexString("void Main.<init>()")});
-  infos.emplace_back(MethodInfo{0x118, 2, DexString("void Main.main(java.lang.String[])")});
+  infos.emplace_back(MethodInfo{0x100, 8, std::string("void Main.<init>()")});
+  infos.emplace_back(MethodInfo{0x118, 2, std::string("void Main.main(java.lang.String[])")});
   ASSERT_EQ(dex_file->GetAllMethodInfos(true), infos);
 }
 
diff --git a/libdexfile/external/include/art_api/dex_file_external.h b/libdexfile/external/include/art_api/dex_file_external.h
index b29e759..b880335 100644
--- a/libdexfile/external/include/art_api/dex_file_external.h
+++ b/libdexfile/external/include/art_api/dex_file_external.h
@@ -20,6 +20,7 @@
 // Dex file external API
 
 #include <sys/types.h>
+#include <stdint.h>
 
 #ifdef __cplusplus
 extern "C" {
@@ -28,59 +29,53 @@
 // This is the stable C ABI that backs art_api::dex below. Structs and functions
 // may only be added here. C++ users should use dex_file_support.h instead.
 
-// Opaque wrapper for an std::string allocated in libdexfile which must be freed
-// using ExtDexFileFreeString.
-struct ExtDexFileString;
-
-// Returns an ExtDexFileString initialized to the given string.
-const struct ExtDexFileString* ExtDexFileMakeString(const char* str, size_t size);
-
-// Returns a pointer to the underlying null-terminated character array and its
-// size for the given ExtDexFileString.
-const char* ExtDexFileGetString(const struct ExtDexFileString* ext_string, /*out*/ size_t* size);
-
-// Frees an ExtDexFileString.
-void ExtDexFileFreeString(const struct ExtDexFileString* ext_string);
-
 struct ExtDexFileMethodInfo {
-  int32_t offset;
-  int32_t len;
-  const struct ExtDexFileString* name;
+  size_t sizeof_struct;  // Size of this structure (to allow future extensions).
+  uint32_t addr;  // Start of dex byte-code relative to the start of the dex file.
+  uint32_t size;  // Size of the dex byte-code in bytes.
+  const char* name;
+  size_t name_size;
+};
+
+enum ExtDexFileError {
+  kExtDexFileOk = 0,
+  kExtDexFileError = 1,  // Unspecified error.
+  kExtDexFileNotEnoughData = 2,
+  kExtDexFileInvalidHeader = 3,
+};
+
+enum ExtDexFileMethodFlags {
+  kExtDexFileWithSignature = 1,
 };
 
 struct ExtDexFile;
 
-// See art_api::dex::DexFile::OpenFromMemory. Returns true on success.
+// Try to open a dex file in the given memory range.
+// If the memory range is too small, larger suggest size is written to the argument.
 int ExtDexFileOpenFromMemory(const void* addr,
                              /*inout*/ size_t* size,
                              const char* location,
-                             /*out*/ const struct ExtDexFileString** error_msg,
                              /*out*/ struct ExtDexFile** ext_dex_file);
 
-// See art_api::dex::DexFile::OpenFromFd. Returns true on success.
-int ExtDexFileOpenFromFd(int fd,
-                         off_t offset,
-                         const char* location,
-                         /*out*/ const struct ExtDexFileString** error_msg,
-                         /*out*/ struct ExtDexFile** ext_dex_file);
+// Callback used to return information about a dex method.
+typedef void ExtDexFileMethodInfoCallback(void* user_data,
+                                          struct ExtDexFileMethodInfo* method_info);
 
-// See art_api::dex::DexFile::GetMethodInfoForOffset. Returns true on success.
+// Find a single dex method based on the given dex offset.
 int ExtDexFileGetMethodInfoForOffset(struct ExtDexFile* ext_dex_file,
-                                     int64_t dex_offset,
-                                     int with_signature,
-                                     /*out*/ struct ExtDexFileMethodInfo* method_info);
+                                     uint32_t dex_offset,
+                                     uint32_t flags,
+                                     ExtDexFileMethodInfoCallback* method_info_cb,
+                                     void* user_data);
 
-typedef void ExtDexFileMethodInfoCallback(const struct ExtDexFileMethodInfo* ext_method_info,
-                                          void* user_data);
-
-// See art_api::dex::DexFile::GetAllMethodInfos.
+// Return all dex methods in the dex file.
 void ExtDexFileGetAllMethodInfos(struct ExtDexFile* ext_dex_file,
-                                 int with_signature,
+                                 uint32_t flags,
                                  ExtDexFileMethodInfoCallback* method_info_cb,
                                  void* user_data);
 
-// Frees an ExtDexFile.
-void ExtDexFileFree(struct ExtDexFile* ext_dex_file);
+// Release all associated memory.
+void ExtDexFileClose(struct ExtDexFile* ext_dex_file);
 
 #ifdef __cplusplus
 }  // extern "C"
diff --git a/libdexfile/external/include/art_api/dex_file_support.h b/libdexfile/external/include/art_api/dex_file_support.h
index 404fa65..3fbf169 100644
--- a/libdexfile/external/include/art_api/dex_file_support.h
+++ b/libdexfile/external/include/art_api/dex_file_support.h
@@ -27,6 +27,7 @@
 #include <vector>
 
 #include <android-base/macros.h>
+#include <android-base/mapped_file.h>
 
 #include "art_api/dex_file_external.h"
 
@@ -44,75 +45,11 @@
 // below.
 void LoadLibdexfileExternal();
 
-// Minimal std::string look-alike for a string returned from libdexfile.
-class DexString final {
- public:
-  DexString(DexString&& dex_str) noexcept : ext_string_(dex_str.ext_string_) {
-    dex_str.ext_string_ = MakeExtDexFileString("", 0);
-  }
-  explicit DexString(const char* str = "")
-      : ext_string_(MakeExtDexFileString(str, std::strlen(str))) {}
-  explicit DexString(std::string_view str)
-      : ext_string_(MakeExtDexFileString(str.data(), str.size())) {}
-  ~DexString() { g_ExtDexFileFreeString(ext_string_); }
-
-  DexString& operator=(DexString&& dex_str) noexcept {
-    std::swap(ext_string_, dex_str.ext_string_);
-    return *this;
-  }
-
-  const char* data() const {
-    size_t ignored;
-    return g_ExtDexFileGetString(ext_string_, &ignored);
-  }
-  const char* c_str() const { return data(); }
-
-  size_t size() const {
-    size_t len;
-    (void)g_ExtDexFileGetString(ext_string_, &len);
-    return len;
-  }
-  size_t length() const { return size(); }
-
-  operator std::string_view() const {
-    size_t len;
-    const char* chars = g_ExtDexFileGetString(ext_string_, &len);
-    return std::string_view(chars, len);
-  }
-
- private:
-  friend bool TryLoadLibdexfileExternal(std::string* error_msg);
-  friend class DexFile;
-  friend bool operator==(const DexString&, const DexString&);
-  explicit DexString(const ExtDexFileString* ext_string) : ext_string_(ext_string) {}
-  const ExtDexFileString* ext_string_;  // Owned instance. Never nullptr.
-
-  // These are initialized by TryLoadLibdexfileExternal.
-  static decltype(ExtDexFileMakeString)* g_ExtDexFileMakeString;
-  static decltype(ExtDexFileGetString)* g_ExtDexFileGetString;
-  static decltype(ExtDexFileFreeString)* g_ExtDexFileFreeString;
-
-  static const struct ExtDexFileString* MakeExtDexFileString(const char* str, size_t size) {
-    if (UNLIKELY(g_ExtDexFileMakeString == nullptr)) {
-      LoadLibdexfileExternal();
-    }
-    return g_ExtDexFileMakeString(str, size);
-  }
-
-  DISALLOW_COPY_AND_ASSIGN(DexString);
-};
-
-inline bool operator==(const DexString& s1, const DexString& s2) {
-  size_t l1, l2;
-  const char* str1 = DexString::g_ExtDexFileGetString(s1.ext_string_, &l1);
-  const char* str2 = DexString::g_ExtDexFileGetString(s2.ext_string_, &l2);
-  // Use memcmp to avoid assumption about absence of null characters in the strings.
-  return l1 == l2 && !std::memcmp(str1, str2, l1);
-}
+using DexString = std::string;
 
 struct MethodInfo {
-  int32_t offset;  // Code offset relative to the start of the dex file header
-  int32_t len;  // Code length
+  uint32_t offset = 0;  // Code offset relative to the start of the dex file header
+  uint32_t len = 0;     // Code length
   DexString name;
 };
 
@@ -126,20 +63,21 @@
 class DexFile {
  public:
   DexFile(DexFile&& dex_file) noexcept {
-    ext_dex_file_ = dex_file.ext_dex_file_;
-    dex_file.ext_dex_file_ = nullptr;
+    std::swap(ext_dex_file_, dex_file.ext_dex_file_);
+    std::swap(map_, dex_file.map_);
   }
 
   explicit DexFile(std::unique_ptr<DexFile>& dex_file) noexcept {
-    ext_dex_file_ = dex_file->ext_dex_file_;
-    dex_file->ext_dex_file_ = nullptr;
-    dex_file.reset(nullptr);
+    std::swap(ext_dex_file_, dex_file->ext_dex_file_);
+    std::swap(map_, dex_file->map_);
+    dex_file.reset();
   }
+
   virtual ~DexFile();
 
   // Interprets a chunk of memory as a dex file. As long as *size is too small,
   // returns nullptr, sets *size to a new size to try again with, and sets
-  // *error_msg to "". That might happen repeatedly. Also returns nullptr
+  // *error_msg. That might happen repeatedly. Also returns nullptr
   // on error in which case *error_msg is set to a nonempty string.
   //
   // location is a string that describes the dex file, and is preferably its
@@ -149,20 +87,7 @@
   static std::unique_ptr<DexFile> OpenFromMemory(const void* addr,
                                                  size_t* size,
                                                  const std::string& location,
-                                                 /*out*/ std::string* error_msg) {
-    if (UNLIKELY(g_ExtDexFileOpenFromMemory == nullptr)) {
-      // Load libdexfile_external.so in this factory function, so instance
-      // methods don't need to check this.
-      LoadLibdexfileExternal();
-    }
-    ExtDexFile* ext_dex_file;
-    const ExtDexFileString* ext_error_msg = nullptr;
-    if (g_ExtDexFileOpenFromMemory(addr, size, location.c_str(), &ext_error_msg, &ext_dex_file)) {
-      return std::unique_ptr<DexFile>(new DexFile(ext_dex_file));
-    }
-    *error_msg = (ext_error_msg == nullptr) ? "" : std::string(DexString(ext_error_msg));
-    return nullptr;
-  }
+                                                 /*out*/ std::string* error_msg);
 
   // mmaps the given file offset in the open fd and reads a dexfile from there.
   // Returns nullptr on error in which case *error_msg is set.
@@ -172,65 +97,39 @@
   static std::unique_ptr<DexFile> OpenFromFd(int fd,
                                              off_t offset,
                                              const std::string& location,
-                                             /*out*/ std::string* error_msg) {
-    if (UNLIKELY(g_ExtDexFileOpenFromFd == nullptr)) {
-      // Load libdexfile_external.so in this factory function, so instance
-      // methods don't need to check this.
-      LoadLibdexfileExternal();
-    }
-    ExtDexFile* ext_dex_file;
-    const ExtDexFileString* ext_error_msg = nullptr;
-    if (g_ExtDexFileOpenFromFd(fd, offset, location.c_str(), &ext_error_msg, &ext_dex_file)) {
-      return std::unique_ptr<DexFile>(new DexFile(ext_dex_file));
-    }
-    *error_msg = std::string(DexString(ext_error_msg));
-    return nullptr;
-  }
+                                             /*out*/ std::string* error_msg);
 
   // Given an offset relative to the start of the dex file header, if there is a
   // method whose instruction range includes that offset then returns info about
   // it, otherwise returns a struct with offset == 0. MethodInfo.name receives
   // the full function signature if with_signature is set, otherwise it gets the
   // class and method name only.
-  MethodInfo GetMethodInfoForOffset(int64_t dex_offset, bool with_signature) {
-    ExtDexFileMethodInfo ext_method_info;
-    if (g_ExtDexFileGetMethodInfoForOffset(ext_dex_file_,
-                                           dex_offset,
-                                           with_signature,
-                                           &ext_method_info)) {
-      return AbsorbMethodInfo(ext_method_info);
-    }
-    return {/*offset=*/0, /*len=*/0, /*name=*/DexString()};
-  }
+  MethodInfo GetMethodInfoForOffset(int64_t dex_offset, bool with_signature);
 
   // Returns info structs about all methods in the dex file. MethodInfo.name
   // receives the full function signature if with_signature is set, otherwise it
   // gets the class and method name only.
-  std::vector<MethodInfo> GetAllMethodInfos(bool with_signature) {
-    MethodInfoVector res;
-    g_ExtDexFileGetAllMethodInfos(ext_dex_file_,
-                                  with_signature,
-                                  AddMethodInfoCallback,
-                                  static_cast<void*>(&res));
-    return res;
-  }
+  std::vector<MethodInfo> GetAllMethodInfos(bool with_signature);
 
  private:
+  static inline MethodInfo AbsorbMethodInfo(const ExtDexFileMethodInfo* info) {
+    return {
+      .offset = info->addr,
+      .len = info->size,
+      .name = std::string(info->name, info->name_size)
+    };
+  }
+
   friend bool TryLoadLibdexfileExternal(std::string* error_msg);
   explicit DexFile(ExtDexFile* ext_dex_file) : ext_dex_file_(ext_dex_file) {}
-  ExtDexFile* ext_dex_file_;  // Owned instance. nullptr only in moved-from zombies.
-
-  typedef std::vector<MethodInfo> MethodInfoVector;
-
-  static MethodInfo AbsorbMethodInfo(const ExtDexFileMethodInfo& ext_method_info);
-  static void AddMethodInfoCallback(const ExtDexFileMethodInfo* ext_method_info, void* user_data);
+  ExtDexFile* ext_dex_file_ = nullptr;  // Owned instance. nullptr only in moved-from zombies.
+  std::unique_ptr<android::base::MappedFile> map_;  // Owned map (if we allocated one).
 
   // These are initialized by TryLoadLibdexfileExternal.
   static decltype(ExtDexFileOpenFromMemory)* g_ExtDexFileOpenFromMemory;
-  static decltype(ExtDexFileOpenFromFd)* g_ExtDexFileOpenFromFd;
   static decltype(ExtDexFileGetMethodInfoForOffset)* g_ExtDexFileGetMethodInfoForOffset;
   static decltype(ExtDexFileGetAllMethodInfos)* g_ExtDexFileGetAllMethodInfos;
-  static decltype(ExtDexFileFree)* g_ExtDexFileFree;
+  static decltype(ExtDexFileClose)* g_ExtDexFileClose;
 
   DISALLOW_COPY_AND_ASSIGN(DexFile);
 };
diff --git a/libdexfile/external/libdexfile_external.map.txt b/libdexfile/external/libdexfile_external.map.txt
index 450b633..e9d12fb 100644
--- a/libdexfile/external/libdexfile_external.map.txt
+++ b/libdexfile/external/libdexfile_external.map.txt
@@ -1,12 +1,8 @@
 LIBDEXFILE_EXTERNAL_1 {
   global:
-    ExtDexFileFree;
-    ExtDexFileFreeString;
+    ExtDexFileClose;
     ExtDexFileGetAllMethodInfos;
     ExtDexFileGetMethodInfoForOffset;
-    ExtDexFileGetString;
-    ExtDexFileMakeString;
-    ExtDexFileOpenFromFd;
     ExtDexFileOpenFromMemory;
   local:
     *;