Merge "Libcore failures for buildbot should now be flagged device_testdex."
diff --git a/build/Android.gtest.mk b/build/Android.gtest.mk
index a926d9a..00055b2 100644
--- a/build/Android.gtest.mk
+++ b/build/Android.gtest.mk
@@ -371,8 +371,8 @@
 
 ART_TEST_MODULES := \
     art_cmdline_tests \
-    art_compiler_tests \
     art_compiler_host_tests \
+    art_compiler_tests \
     art_dex2oat_tests \
     art_dexanalyze_tests \
     art_dexdiag_tests \
@@ -383,12 +383,14 @@
     art_hiddenapi_tests \
     art_imgdiag_tests \
     art_libartbase_tests \
+    art_libdexfile_external_tests \
+    art_libdexfile_support_tests \
     art_libdexfile_tests \
     art_libprofile_tests \
     art_oatdump_tests \
     art_profman_tests \
-    art_runtime_tests \
     art_runtime_compiler_tests \
+    art_runtime_tests \
     art_sigchain_tests \
 
 ART_TARGET_GTEST_FILES := $(foreach m,$(ART_TEST_MODULES),\
diff --git a/libdexfile/Android.bp b/libdexfile/Android.bp
index 9c48aa2..2f56a3d 100644
--- a/libdexfile/Android.bp
+++ b/libdexfile/Android.bp
@@ -176,6 +176,36 @@
     },
 }
 
+art_cc_test {
+    name: "art_libdexfile_tests",
+    defaults: [
+        "art_gtest_defaults",
+    ],
+    srcs: [
+        "dex/art_dex_file_loader_test.cc",
+        "dex/class_accessor_test.cc",
+        "dex/code_item_accessors_test.cc",
+        "dex/compact_dex_file_test.cc",
+        "dex/compact_offset_table_test.cc",
+        "dex/descriptors_names_test.cc",
+        "dex/test_dex_file_builder_test.cc",
+        "dex/dex_file_loader_test.cc",
+        "dex/dex_file_verifier_test.cc",
+        "dex/dex_instruction_test.cc",
+        "dex/primitive_test.cc",
+        "dex/string_reference_test.cc",
+        "dex/type_lookup_table_test.cc",
+        "dex/utf_test.cc",
+    ],
+    shared_libs: [
+        "libbacktrace",
+        "libziparchive",
+    ],
+    include_dirs: [
+        "external/zlib",
+    ],
+}
+
 cc_library_headers {
     name: "libdexfile_external_headers",
     host_supported: true,
@@ -227,6 +257,16 @@
     },
 }
 
+art_cc_test {
+    name: "art_libdexfile_external_tests",
+    host_supported: true,
+    test_per_src: true,  // For consistency with other ART gtests.
+    srcs: [
+        "external/dex_file_ext_c_test.c",
+    ],
+    header_libs: ["libdexfile_external_headers"],
+}
+
 // Support library with a C++ API for accessing the libdexfile API for external
 // (non-ART) users. They should link to their own instance of this (either
 // statically or through linker namespaces).
@@ -242,31 +282,16 @@
 }
 
 art_cc_test {
-    name: "art_libdexfile_tests",
-    defaults: [
-        "art_gtest_defaults",
-    ],
+    name: "art_libdexfile_support_tests",
+    host_supported: true,
+    test_per_src: true,  // For consistency with other ART gtests.
     srcs: [
-        "dex/art_dex_file_loader_test.cc",
-        "dex/class_accessor_test.cc",
-        "dex/code_item_accessors_test.cc",
-        "dex/compact_dex_file_test.cc",
-        "dex/compact_offset_table_test.cc",
-        "dex/descriptors_names_test.cc",
-        "dex/test_dex_file_builder_test.cc",
-        "dex/dex_file_loader_test.cc",
-        "dex/dex_file_verifier_test.cc",
-        "dex/dex_instruction_test.cc",
-        "dex/primitive_test.cc",
-        "dex/string_reference_test.cc",
-        "dex/type_lookup_table_test.cc",
-        "dex/utf_test.cc",
+        "external/dex_file_supp_test.cc",
     ],
     shared_libs: [
-        "libbacktrace",
-        "libziparchive",
-    ],
-    include_dirs: [
-        "external/zlib",
+        "libartbase",
+        "libbase",
+        "libdexfile_external",
+        "libdexfile_support",
     ],
 }
diff --git a/libdexfile/external/dex_file_ext.cc b/libdexfile/external/dex_file_ext.cc
index 7bf01a8..e1b7874 100644
--- a/libdexfile/external/dex_file_ext.cc
+++ b/libdexfile/external/dex_file_ext.cc
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#include "art_api/dex_file_external.h"
+
 #include <inttypes.h>
 #include <stdint.h>
 #include <sys/mman.h>
@@ -39,18 +41,9 @@
 #include <dex/dex_file-inl.h>
 #include <dex/dex_file_loader.h>
 
-#include "art_api/dex_file_support.h"
-
-extern "C" class ExtDexFileString {
- public:
-  const std::string str_;
-};
-
 namespace art {
 namespace {
 
-const ExtDexFileString empty_string{""};
-
 struct MethodCacheEntry {
   int32_t offset;  // Offset relative to the start of the dex file header.
   int32_t len;
@@ -77,11 +70,17 @@
 
 extern "C" {
 
-const ExtDexFileString* ExtDexFileMakeString(const char* str) {
-  if (str[0] == '\0') {
-    return &art::empty_string;
+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{str};
+  return new ExtDexFileString{std::string(str, size)};
 }
 
 const char* ExtDexFileGetString(const ExtDexFileString* ext_string, /*out*/ size_t* size) {
@@ -92,14 +91,15 @@
 
 void ExtDexFileFreeString(const ExtDexFileString* ext_string) {
   DCHECK(ext_string != nullptr);
-  if (ext_string != &art::empty_string) {
+  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*.
-class ExtDexFile {
+struct ExtDexFile {
+ private:
   // Method cache for GetMethodInfoForOffset. This is populated as we iterate
   // sequentially through the class defs. MethodCacheEntry.name is only set for
   // methods returned by GetMethodInfoForOffset.
diff --git a/libdexfile/external/dex_file_ext_c_test.c b/libdexfile/external/dex_file_ext_c_test.c
new file mode 100644
index 0000000..ad0737a
--- /dev/null
+++ b/libdexfile/external/dex_file_ext_c_test.c
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+
+/* The main purpose of this test is to ensure this C header compiles in C, so
+ * that no C++ features inadvertently leak into the C ABI. */
+#include "art_api/dex_file_external.h"
+
+static const char gtest_output_arg[] = "--gtest_output=xml:";
+static const char gtest_output_xml[] = "\
+<?xml version=\"1.0\"?>\n\
+<testsuites tests=\"0\" failures=\"0\" disabled=\"0\" errors=\"0\" name=\"AllTests\">";
+
+/* Writes a dummy gtest xml report to the given path. */
+static int write_gtest_output_xml(char* gtest_output_path) {
+  FILE* output_fd = fopen(gtest_output_path, "w");
+  if (output_fd == NULL) {
+    fprintf(stderr, "Failed to open %s: %s\n", gtest_output_path, strerror(errno));
+    return 1;
+  }
+  if (fprintf(output_fd, gtest_output_xml) != sizeof(gtest_output_xml) - 1) {
+    fprintf(stderr, "Failed to write %s: %s\n", gtest_output_path, strerror(errno));
+    return 1;
+  }
+  if (fclose(output_fd) != 0) {
+    fprintf(stderr, "Failed to close %s: %s\n", gtest_output_path, strerror(errno));
+    return 1;
+  }
+  return 0;
+}
+
+int main(int argc, char** argv) {
+  if (argc >= 1 && strncmp(argv[1], gtest_output_arg, sizeof(gtest_output_arg) - 1) == 0) {
+    /* The ART gtest framework expects all tests to understand --gtest_output. */
+    return write_gtest_output_xml(argv[1] + sizeof(gtest_output_arg) - 1);
+  }
+  return 0;
+}
diff --git a/libdexfile/external/dex_file_supp_test.cc b/libdexfile/external/dex_file_supp_test.cc
new file mode 100644
index 0000000..3dd08c0
--- /dev/null
+++ b/libdexfile/external/dex_file_supp_test.cc
@@ -0,0 +1,283 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <sys/types.h>
+
+#include <memory>
+#include <string>
+#include <string_view>
+
+#include <android-base/file.h>
+#include <dex/dex_file.h>
+#include <gtest/gtest.h>
+
+#include "art_api/dex_file_support.h"
+
+namespace art_api {
+namespace dex {
+
+static constexpr uint32_t kDexData[] = {
+    0x0a786564, 0x00383330, 0xc98b3ab8, 0xf3749d94, 0xaecca4d8, 0xffc7b09a, 0xdca9ca7f, 0x5be5deab,
+    0x00000220, 0x00000070, 0x12345678, 0x00000000, 0x00000000, 0x0000018c, 0x00000008, 0x00000070,
+    0x00000004, 0x00000090, 0x00000002, 0x000000a0, 0x00000000, 0x00000000, 0x00000003, 0x000000b8,
+    0x00000001, 0x000000d0, 0x00000130, 0x000000f0, 0x00000122, 0x0000012a, 0x00000132, 0x00000146,
+    0x00000151, 0x00000154, 0x00000158, 0x0000016d, 0x00000001, 0x00000002, 0x00000004, 0x00000006,
+    0x00000004, 0x00000002, 0x00000000, 0x00000005, 0x00000002, 0x0000011c, 0x00000000, 0x00000000,
+    0x00010000, 0x00000007, 0x00000001, 0x00000000, 0x00000000, 0x00000001, 0x00000001, 0x00000000,
+    0x00000003, 0x00000000, 0x0000017e, 0x00000000, 0x00010001, 0x00000001, 0x00000173, 0x00000004,
+    0x00021070, 0x000e0000, 0x00010001, 0x00000000, 0x00000178, 0x00000001, 0x0000000e, 0x00000001,
+    0x3c060003, 0x74696e69, 0x4c06003e, 0x6e69614d, 0x4c12003b, 0x6176616a, 0x6e616c2f, 0x624f2f67,
+    0x7463656a, 0x4d09003b, 0x2e6e6961, 0x6176616a, 0x00560100, 0x004c5602, 0x6a4c5b13, 0x2f617661,
+    0x676e616c, 0x7274532f, 0x3b676e69, 0x616d0400, 0x01006e69, 0x000e0700, 0x07000103, 0x0000000e,
+    0x81000002, 0x01f00480, 0x02880901, 0x0000000c, 0x00000000, 0x00000001, 0x00000000, 0x00000001,
+    0x00000008, 0x00000070, 0x00000002, 0x00000004, 0x00000090, 0x00000003, 0x00000002, 0x000000a0,
+    0x00000005, 0x00000003, 0x000000b8, 0x00000006, 0x00000001, 0x000000d0, 0x00002001, 0x00000002,
+    0x000000f0, 0x00001001, 0x00000001, 0x0000011c, 0x00002002, 0x00000008, 0x00000122, 0x00002003,
+    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());
+  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());
+  EXPECT_EQ(std::string_view(s2), "foo");
+}
+
+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());
+}
+
+TEST(DexFileTest, from_memory_file_too_small) {
+  size_t size = sizeof(art::DexFile::Header);
+  std::string error_msg;
+  EXPECT_EQ(DexFile::OpenFromMemory(kDexData, &size, "", &error_msg), nullptr);
+  EXPECT_EQ(size, sizeof(kDexData));
+  EXPECT_TRUE(error_msg.empty());
+}
+
+static std::unique_ptr<DexFile> GetTestDexData() {
+  size_t size = sizeof(kDexData);
+  std::string error_msg;
+  std::unique_ptr<DexFile> dex_file = DexFile::OpenFromMemory(kDexData, &size, "", &error_msg);
+  EXPECT_TRUE(error_msg.empty());
+  return dex_file;
+}
+
+TEST(DexFileTest, from_memory) {
+  EXPECT_NE(GetTestDexData(), nullptr);
+}
+
+TEST(DexFileTest, from_fd_header_too_small) {
+  TemporaryFile tf;
+  ASSERT_NE(tf.fd, -1);
+  ASSERT_EQ(sizeof(art::DexFile::Header) - 1,
+            static_cast<size_t>(
+                TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(art::DexFile::Header) - 1))));
+
+  std::string error_msg;
+  EXPECT_EQ(DexFile::OpenFromFd(tf.fd, 0, tf.path, &error_msg), nullptr);
+  EXPECT_FALSE(error_msg.empty());
+}
+
+TEST(DexFileTest, from_fd_file_too_small) {
+  TemporaryFile tf;
+  ASSERT_NE(tf.fd, -1);
+  ASSERT_EQ(sizeof(art::DexFile::Header),
+            static_cast<size_t>(
+                TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(art::DexFile::Header)))));
+
+  std::string error_msg;
+  EXPECT_EQ(DexFile::OpenFromFd(tf.fd, 0, tf.path, &error_msg), nullptr);
+  EXPECT_FALSE(error_msg.empty());
+}
+
+TEST(DexFileTest, from_fd) {
+  TemporaryFile tf;
+  ASSERT_NE(tf.fd, -1);
+  ASSERT_EQ(sizeof(kDexData),
+            static_cast<size_t>(TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(kDexData)))));
+
+  std::string error_msg;
+  EXPECT_NE(DexFile::OpenFromFd(tf.fd, 0, tf.path, &error_msg), nullptr);
+  EXPECT_TRUE(error_msg.empty());
+}
+
+TEST(DexFileTest, from_fd_non_zero_offset) {
+  TemporaryFile tf;
+  ASSERT_NE(tf.fd, -1);
+  ASSERT_EQ(0x100, lseek(tf.fd, 0x100, SEEK_SET));
+  ASSERT_EQ(sizeof(kDexData),
+            static_cast<size_t>(TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(kDexData)))));
+
+  std::string error_msg;
+  EXPECT_NE(DexFile::OpenFromFd(tf.fd, 0x100, tf.path, &error_msg), nullptr);
+  EXPECT_TRUE(error_msg.empty());
+}
+
+TEST(DexFileTest, get_method_info_for_offset_without_signature) {
+  std::unique_ptr<DexFile> dex_file = GetTestDexData();
+  ASSERT_NE(dex_file, nullptr);
+
+  MethodInfo info = dex_file->GetMethodInfoForOffset(0x102, false);
+  EXPECT_EQ(info.offset, int32_t{0x100});
+  EXPECT_EQ(info.len, int32_t{8});
+  EXPECT_STREQ(info.name.data(), "Main.<init>");
+
+  info = dex_file->GetMethodInfoForOffset(0x118, false);
+  EXPECT_EQ(info.offset, int32_t{0x118});
+  EXPECT_EQ(info.len, int32_t{2});
+  EXPECT_STREQ(info.name.data(), "Main.main");
+
+  // Retrieve a cached result.
+  info = dex_file->GetMethodInfoForOffset(0x104, false);
+  EXPECT_EQ(info.offset, int32_t{0x100});
+  EXPECT_EQ(info.len, int32_t{8});
+  EXPECT_STREQ(info.name.data(), "Main.<init>");
+}
+
+TEST(DexFileTest, get_method_info_for_offset_with_signature) {
+  std::unique_ptr<DexFile> dex_file = GetTestDexData();
+  ASSERT_NE(dex_file, nullptr);
+
+  MethodInfo info = dex_file->GetMethodInfoForOffset(0x102, true);
+  EXPECT_EQ(info.offset, int32_t{0x100});
+  EXPECT_EQ(info.len, int32_t{8});
+  EXPECT_STREQ(info.name.data(), "void Main.<init>()");
+
+  info = dex_file->GetMethodInfoForOffset(0x118, true);
+  EXPECT_EQ(info.offset, int32_t{0x118});
+  EXPECT_EQ(info.len, int32_t{2});
+  EXPECT_STREQ(info.name.data(), "void Main.main(java.lang.String[])");
+
+  // Retrieve a cached result.
+  info = dex_file->GetMethodInfoForOffset(0x104, true);
+  EXPECT_EQ(info.offset, int32_t{0x100});
+  EXPECT_EQ(info.len, int32_t{8});
+  EXPECT_STREQ(info.name.data(), "void Main.<init>()");
+
+  // with_signature doesn't affect the cache.
+  info = dex_file->GetMethodInfoForOffset(0x104, false);
+  EXPECT_EQ(info.offset, int32_t{0x100});
+  EXPECT_EQ(info.len, int32_t{8});
+  EXPECT_STREQ(info.name.data(), "Main.<init>");
+}
+
+TEST(DexFileTest, get_method_info_for_offset_boundaries) {
+  std::unique_ptr<DexFile> dex_file = GetTestDexData();
+  ASSERT_NE(dex_file, nullptr);
+
+  MethodInfo info = dex_file->GetMethodInfoForOffset(0x100000, false);
+  EXPECT_EQ(info.offset, int32_t{0});
+
+  info = dex_file->GetMethodInfoForOffset(0x99, false);
+  EXPECT_EQ(info.offset, int32_t{0});
+  info = dex_file->GetMethodInfoForOffset(0x100, false);
+  EXPECT_EQ(info.offset, int32_t{0x100});
+  info = dex_file->GetMethodInfoForOffset(0x107, false);
+  EXPECT_EQ(info.offset, int32_t{0x100});
+  info = dex_file->GetMethodInfoForOffset(0x108, false);
+  EXPECT_EQ(info.offset, int32_t{0});
+
+  // Make sure that once the whole dex file has been cached, no problems occur.
+  info = dex_file->GetMethodInfoForOffset(0x98, false);
+  EXPECT_EQ(info.offset, int32_t{0});
+
+  // Choose a value that is in the cached map, but not in a valid method.
+  info = dex_file->GetMethodInfoForOffset(0x110, false);
+  EXPECT_EQ(info.offset, int32_t{0});
+}
+
+TEST(DexFileTest, get_all_method_infos_without_signature) {
+  std::unique_ptr<DexFile> dex_file = GetTestDexData();
+  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")});
+  ASSERT_EQ(dex_file->GetAllMethodInfos(false), infos);
+}
+
+TEST(DexFileTest, get_all_method_infos_with_signature) {
+  std::unique_ptr<DexFile> dex_file = GetTestDexData();
+  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[])")});
+  ASSERT_EQ(dex_file->GetAllMethodInfos(true), infos);
+}
+
+TEST(DexFileTest, move_construct) {
+  std::unique_ptr<DexFile> dex_file = GetTestDexData();
+  ASSERT_NE(dex_file, nullptr);
+
+  auto df1 = DexFile(std::move(*dex_file.release()));
+  auto df2 = DexFile(std::move(df1));
+
+  MethodInfo info = df2.GetMethodInfoForOffset(0x100, false);
+  EXPECT_EQ(info.offset, int32_t{0x100});
+}
+
+}  // namespace dex
+}  // namespace art_api
diff --git a/libdexfile/external/include/art_api/dex_file_external.h b/libdexfile/external/include/art_api/dex_file_external.h
new file mode 100644
index 0000000..b29e759
--- /dev/null
+++ b/libdexfile/external/include/art_api/dex_file_external.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_LIBDEXFILE_EXTERNAL_INCLUDE_ART_API_DEX_FILE_EXTERNAL_H_
+#define ART_LIBDEXFILE_EXTERNAL_INCLUDE_ART_API_DEX_FILE_EXTERNAL_H_
+
+// Dex file external API
+
+#include <sys/types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// 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;
+};
+
+struct ExtDexFile;
+
+// See art_api::dex::DexFile::OpenFromMemory. Returns true on success.
+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);
+
+// See art_api::dex::DexFile::GetMethodInfoForOffset. Returns true on success.
+int ExtDexFileGetMethodInfoForOffset(struct ExtDexFile* ext_dex_file,
+                                     int64_t dex_offset,
+                                     int with_signature,
+                                     /*out*/ struct ExtDexFileMethodInfo* method_info);
+
+typedef void ExtDexFileMethodInfoCallback(const struct ExtDexFileMethodInfo* ext_method_info,
+                                          void* user_data);
+
+// See art_api::dex::DexFile::GetAllMethodInfos.
+void ExtDexFileGetAllMethodInfos(struct ExtDexFile* ext_dex_file,
+                                 int with_signature,
+                                 ExtDexFileMethodInfoCallback* method_info_cb,
+                                 void* user_data);
+
+// Frees an ExtDexFile.
+void ExtDexFileFree(struct ExtDexFile* ext_dex_file);
+
+#ifdef __cplusplus
+}  // extern "C"
+#endif
+
+#endif  // ART_LIBDEXFILE_EXTERNAL_INCLUDE_ART_API_DEX_FILE_EXTERNAL_H_
diff --git a/libdexfile/external/include/art_api/dex_file_support.h b/libdexfile/external/include/art_api/dex_file_support.h
index 99d60d1..ddd9143 100644
--- a/libdexfile/external/include/art_api/dex_file_support.h
+++ b/libdexfile/external/include/art_api/dex_file_support.h
@@ -17,9 +17,7 @@
 #ifndef ART_LIBDEXFILE_EXTERNAL_INCLUDE_ART_API_DEX_FILE_SUPPORT_H_
 #define ART_LIBDEXFILE_EXTERNAL_INCLUDE_ART_API_DEX_FILE_SUPPORT_H_
 
-// Dex file external API
-
-#include <sys/types.h>
+// C++ wrapper for the dex file external API.
 
 #include <cstring>
 #include <memory>
@@ -29,69 +27,7 @@
 
 #include <android-base/macros.h>
 
-extern "C" {
-
-// This is the stable C ABI that backs art_api::dex below. Structs and functions
-// may only be added here.
-// TODO(b/120978655): Move this to a separate pure C header.
-//
-// Clients should use the C++ wrappers in art_api::dex instead.
-
-// Opaque wrapper for an std::string allocated in libdexfile which must be freed
-// using ExtDexFileFreeString.
-class ExtDexFileString;
-
-// Returns an ExtDexFileString initialized to the given string.
-const ExtDexFileString* ExtDexFileMakeString(const char* str);
-
-// Returns a pointer to the underlying null-terminated character array and its
-// size for the given ExtDexFileString.
-const char* ExtDexFileGetString(const ExtDexFileString* ext_string, /*out*/ size_t* size);
-
-// Frees an ExtDexFileString.
-void ExtDexFileFreeString(const ExtDexFileString* ext_string);
-
-struct ExtDexFileMethodInfo {
-  int32_t offset;
-  int32_t len;
-  const ExtDexFileString* name;
-};
-
-class ExtDexFile;
-
-// See art_api::dex::DexFile::OpenFromMemory. Returns true on success.
-int ExtDexFileOpenFromMemory(const void* addr,
-                             /*inout*/ size_t* size,
-                             const char* location,
-                             /*out*/ const ExtDexFileString** error_msg,
-                             /*out*/ 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 ExtDexFileString** error_msg,
-                         /*out*/ ExtDexFile** ext_dex_file);
-
-// See art_api::dex::DexFile::GetMethodInfoForOffset. Returns true on success.
-int ExtDexFileGetMethodInfoForOffset(ExtDexFile* ext_dex_file,
-                                     int64_t dex_offset,
-                                     int with_signature,
-                                     /*out*/ ExtDexFileMethodInfo* method_info);
-
-typedef void ExtDexFileMethodInfoCallback(const ExtDexFileMethodInfo* ext_method_info,
-                                          void* user_data);
-
-// See art_api::dex::DexFile::GetAllMethodInfos.
-void ExtDexFileGetAllMethodInfos(ExtDexFile* ext_dex_file,
-                                 int with_signature,
-                                 ExtDexFileMethodInfoCallback* method_info_cb,
-                                 void* user_data);
-
-// Frees an ExtDexFile.
-void ExtDexFileFree(ExtDexFile* ext_dex_file);
-
-}  // extern "C"
+#include "art_api/dex_file_external.h"
 
 namespace art_api {
 namespace dex {
@@ -100,7 +36,10 @@
 class DexString final {
  public:
   DexString(DexString&& dex_str) noexcept { ReplaceExtString(std::move(dex_str)); }
-  explicit DexString(const char* str = "") : ext_string_(ExtDexFileMakeString(str)) {}
+  explicit DexString(const char* str = "")
+      : ext_string_(ExtDexFileMakeString(str, std::strlen(str))) {}
+  explicit DexString(std::string_view str)
+      : ext_string_(ExtDexFileMakeString(str.data(), str.size())) {}
   ~DexString() { ExtDexFileFreeString(ext_string_); }
 
   DexString& operator=(DexString&& dex_str) noexcept {
@@ -135,7 +74,7 @@
 
   void ReplaceExtString(DexString&& dex_str) {
     ext_string_ = dex_str.ext_string_;
-    dex_str.ext_string_ = ExtDexFileMakeString("");
+    dex_str.ext_string_ = ExtDexFileMakeString("", 0);
   }
 
   DISALLOW_COPY_AND_ASSIGN(DexString);