Merge "Refine art/build/apex/runtests.sh's pretty printing options."
diff --git a/adbconnection/adbconnection.cc b/adbconnection/adbconnection.cc
index cf35914..b6d6600 100644
--- a/adbconnection/adbconnection.cc
+++ b/adbconnection/adbconnection.cc
@@ -476,7 +476,6 @@
   int rc = TEMP_FAILURE_RETRY(recvmsg(control_sock_, &msg, 0));
 
   if (rc <= 0) {
-    PLOG(WARNING) << "Receiving file descriptor from ADB failed (socket " << control_sock_ << ")";
     return android::base::unique_fd(-1);
   } else {
     VLOG(jdwp) << "Fds have been received from ADB!";
@@ -624,7 +623,6 @@
           android::base::unique_fd new_fd(ReadFdFromAdb());
           if (new_fd == -1) {
             // Something went wrong. We need to retry getting the control socket.
-            PLOG(ERROR) << "Something went wrong getting fds from adb. Retry!";
             control_sock_.reset();
             break;
           } else if (adb_connection_socket_ != -1) {
diff --git a/build/Android.gtest.mk b/build/Android.gtest.mk
index 468eec6..1bcca7c 100644
--- a/build/Android.gtest.mk
+++ b/build/Android.gtest.mk
@@ -452,12 +452,7 @@
     $$(gtest_exe) \
     $$($(3)TARGET_OUT_SHARED_LIBRARIES)/libjavacore.so \
     $$($(3)TARGET_OUT_SHARED_LIBRARIES)/libopenjdkd.so \
-    $$(TARGET_OUT_JAVA_LIBRARIES)/core-libart-testdex.jar \
-    $$(TARGET_OUT_JAVA_LIBRARIES)/core-oj-testdex.jar \
-    $$(TARGET_OUT_JAVA_LIBRARIES)/core-simple-testdex.jar \
-    $$(TARGET_OUT_JAVA_LIBRARIES)/conscrypt-testdex.jar \
-    $$(TARGET_OUT_JAVA_LIBRARIES)/okhttp-testdex.jar \
-    $$(TARGET_OUT_JAVA_LIBRARIES)/bouncycastle-testdex.jar
+    $$(foreach jar,$$(TARGET_TEST_CORE_JARS),$$(TARGET_OUT_JAVA_LIBRARIES)/$$(jar).jar)
 
   ART_TEST_TARGET_GTEST_DEPENDENCIES += $$(gtest_deps)
 
@@ -543,7 +538,7 @@
 # under ASAN.
 $$(gtest_output): $$(gtest_exe) $$(gtest_deps)
 	$(hide) ($$(call ART_TEST_SKIP,$$(NAME)) && set -o pipefail && \
-		ASAN_OPTIONS=detect_leaks=1 timeout -k 120s -s SIGRTMIN+2 3600s
+		ASAN_OPTIONS=detect_leaks=1 timeout -k 120s -s SIGRTMIN+2 3600s \
 			$(HOST_OUT_EXECUTABLES)/timeout_dumper \
 				$$< --gtest_output=xml:$$@ 2>&1 | tee $$<.tmp.out >&2 && \
 		{ $$(call ART_TEST_PASSED,$$(NAME)) ; rm $$<.tmp.out ; }) || \
diff --git a/libartbase/Android.bp b/libartbase/Android.bp
index 58d12a1..c3fb5fd 100644
--- a/libartbase/Android.bp
+++ b/libartbase/Android.bp
@@ -177,9 +177,6 @@
     header_libs: [
         "libnativehelper_header_only",
     ],
-    include_dirs: [
-        "external/icu/icu4c/source/common",
-    ],
 }
 
 art_cc_test {
diff --git a/libartbase/base/common_art_test.cc b/libartbase/base/common_art_test.cc
index 4e38490..46724ee 100644
--- a/libartbase/base/common_art_test.cc
+++ b/libartbase/base/common_art_test.cc
@@ -26,7 +26,6 @@
 #include "android-base/stringprintf.h"
 #include "android-base/strings.h"
 #include "android-base/unique_fd.h"
-#include <unicode/uvernum.h>
 
 #include "art_field-inl.h"
 #include "base/file_utils.h"
diff --git a/libdexfile/Android.bp b/libdexfile/Android.bp
index 7f25f02..4d6aa5c 100644
--- a/libdexfile/Android.bp
+++ b/libdexfile/Android.bp
@@ -131,6 +131,71 @@
     ],
 }
 
+cc_library_headers {
+    name: "libdexfile_external_headers",
+    host_supported: true,
+    header_libs: ["libbase_headers"],
+    export_header_lib_headers: ["libbase_headers"],
+    export_include_dirs: ["external/include"],
+
+    target: {
+        windows: {
+            enabled: true,
+        },
+    },
+}
+
+cc_library {
+    name: "libdexfile_external",
+    host_supported: true,
+    srcs: [
+        "external/dex_file_ext.cc",
+    ],
+    header_libs: ["libdexfile_external_headers"],
+    shared_libs: [
+        "libbase",
+        "libdexfile",
+    ],
+
+    // TODO(b/120670568): Enable this when linking bug is fixed.
+    // stubs: {
+    //     symbol_file: "external/libdexfile_external.map.txt",
+    //     versions: ["1"],
+    // },
+
+    // Hide symbols using version scripts for targets that support it, i.e. all
+    // but Darwin.
+    // TODO(b/120670568): Clean this up when stubs above is enabled.
+    target: {
+        android: {
+            version_script: "external/libdexfile_external.map.txt",
+        },
+        linux_bionic: {
+            version_script: "external/libdexfile_external.map.txt",
+        },
+        linux_glibc: {
+            version_script: "external/libdexfile_external.map.txt",
+        },
+        windows: {
+            version_script: "external/libdexfile_external.map.txt",
+        },
+    },
+}
+
+// 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).
+cc_library {
+    name: "libdexfile_support",
+    host_supported: true,
+    srcs: [
+        "external/dex_file_supp.cc",
+    ],
+    header_libs: ["libdexfile_external_headers"],
+    shared_libs: ["libdexfile_external"],
+    export_header_lib_headers: ["libdexfile_external_headers"],
+}
+
 art_cc_test {
     name: "art_libdexfile_tests",
     defaults: [
diff --git a/libdexfile/dex/art_dex_file_loader.cc b/libdexfile/dex/art_dex_file_loader.cc
index 20a519b..ae1322d 100644
--- a/libdexfile/dex/art_dex_file_loader.cc
+++ b/libdexfile/dex/art_dex_file_loader.cc
@@ -156,14 +156,16 @@
   return false;
 }
 
-std::unique_ptr<const DexFile> ArtDexFileLoader::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 {
+std::unique_ptr<const DexFile> ArtDexFileLoader::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,
+    std::unique_ptr<DexFileContainer> container) const {
   ScopedTrace trace(std::string("Open dex file from RAM ") + location);
   return OpenCommon(base,
                     size,
@@ -175,7 +177,7 @@
                     verify,
                     verify_checksum,
                     error_msg,
-                    /*container=*/ nullptr,
+                    std::move(container),
                     /*verify_result=*/ nullptr);
 }
 
diff --git a/libdexfile/dex/art_dex_file_loader.h b/libdexfile/dex/art_dex_file_loader.h
index 40d4673..d41eac5 100644
--- a/libdexfile/dex/art_dex_file_loader.h
+++ b/libdexfile/dex/art_dex_file_loader.h
@@ -54,14 +54,16 @@
                             bool* only_contains_uncompressed_dex = nullptr) const override;
 
   // Opens .dex file, backed by existing memory
-  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 override;
+  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,
+      std::unique_ptr<DexFileContainer> container = nullptr) const override;
 
   // Opens .dex file that has been memory-mapped by the caller.
   std::unique_ptr<const DexFile> Open(const std::string& location,
diff --git a/libdexfile/dex/dex_file_loader.cc b/libdexfile/dex/dex_file_loader.cc
index 3667c8c..1884bcf 100644
--- a/libdexfile/dex/dex_file_loader.cc
+++ b/libdexfile/dex/dex_file_loader.cc
@@ -212,14 +212,16 @@
   return false;
 }
 
-std::unique_ptr<const DexFile> DexFileLoader::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 {
+std::unique_ptr<const DexFile> DexFileLoader::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,
+    std::unique_ptr<DexFileContainer> container) const {
   return OpenCommon(base,
                     size,
                     /*data_base=*/ nullptr,
@@ -230,7 +232,7 @@
                     verify,
                     verify_checksum,
                     error_msg,
-                    /*container=*/ nullptr,
+                    std::move(container),
                     /*verify_result=*/ nullptr);
 }
 
diff --git a/libdexfile/dex/dex_file_loader.h b/libdexfile/dex/dex_file_loader.h
index 8fc836e..49e177f 100644
--- a/libdexfile/dex/dex_file_loader.h
+++ b/libdexfile/dex/dex_file_loader.h
@@ -121,14 +121,16 @@
                                     bool* zip_file_only_contains_uncompress_dex = nullptr) 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;
+  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,
+      std::unique_ptr<DexFileContainer> container = nullptr) const;
 
   // Open a dex file with a separate data section.
   virtual std::unique_ptr<const DexFile> OpenWithDataSection(
diff --git a/libdexfile/external/dex_file_ext.cc b/libdexfile/external/dex_file_ext.cc
new file mode 100644
index 0000000..3c193f4
--- /dev/null
+++ b/libdexfile/external/dex_file_ext.cc
@@ -0,0 +1,346 @@
+/*
+ * 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.
+ */
+
+#include <inttypes.h>
+#include <stdint.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <cerrno>
+#include <cstring>
+#include <map>
+#include <memory>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include <android-base/logging.h>
+#include <android-base/macros.h>
+#include <android-base/mapped_file.h>
+#include <android-base/stringprintf.h>
+
+#include <dex/class_accessor-inl.h>
+#include <dex/code_item_accessors-inl.h>
+#include <dex/dex_file-inl.h>
+#include <dex/dex_file_loader.h>
+
+#include "art_api/ext_dex_file.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;
+  int32_t index;  // Method index.
+  std::string name;  // Method name. Not filled in for all cache entries.
+};
+
+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" {
+
+const ExtDexFileString* ExtDexFileMakeString(const char* str) {
+  if (str[0] == '\0') {
+    return &art::empty_string;
+  }
+  return new ExtDexFileString{str};
+}
+
+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 != &art::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 {
+  // 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.
+  std::map<int32_t, art::MethodCacheEntry> method_cache_;
+
+  // Index of first class def for which method_cache_ isn't complete.
+  uint32_t class_def_index_ = 0;
+
+ 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) {
+    // 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;
+    }
+
+    for (; class_def_index_ < dex_file_->NumClassDefs(); class_def_index_++) {
+      art::ClassAccessor accessor(*dex_file_, class_def_index_);
+
+      for (const art::ClassAccessor::Method& method : accessor.GetMethods()) {
+        art::CodeItemInstructionAccessor code = method.GetInstructions();
+        if (!code.HasCodeItem()) {
+          continue;
+        }
+
+        int32_t offset = reinterpret_cast<const uint8_t*>(code.Insns()) - dex_file_->Begin();
+        int32_t len = code.InsnsSizeInBytes();
+        int32_t index = method.GetIndex();
+        auto res =
+            method_cache_.emplace(offset + len, art::MethodCacheEntry{offset, len, index, ""});
+        if (offset <= dex_offset && dex_offset < offset + len) {
+          return &res.first->second;
+        }
+      }
+    }
+
+    return nullptr;
+  }
+
+  const std::string& GetMethodName(art::MethodCacheEntry& entry) {
+    if (entry.name.empty()) {
+      entry.name = dex_file_->PrettyMethod(entry.index, false);
+    }
+    return entry.name;
+  }
+};
+
+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;
+  }
+
+  const art::DexFile::Header* header = reinterpret_cast<const art::DexFile::Header*>(addr);
+  uint32_t file_size = header->file_size_;
+  if (art::CompactDexFile::IsMagicValid(header->magic_)) {
+    // Compact dex files store the data section separately so that it can be shared.
+    // Therefore we need to extend the read memory range to include it.
+    // TODO: This might be wasteful as we might read data in between as well.
+    //       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;
+    }
+    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;
+  }
+
+  if (*size < file_size) {
+    *size = file_size;
+    *ext_error_msg = nullptr;
+    return false;
+  }
+
+  std::string loc_str(location);
+  art::DexFileLoader loader;
+  std::string error_msg;
+  std::unique_ptr<const art::DexFile> dex_file = loader.Open(static_cast<const uint8_t*>(addr),
+                                                             *size,
+                                                             loc_str,
+                                                             header->checksum_,
+                                                             /*oat_dex_file=*/nullptr,
+                                                             /*verify=*/false,
+                                                             /*verify_checksum=*/false,
+                                                             &error_msg);
+  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;
+}
+
+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;
+}
+
+int ExtDexFileGetMethodInfoForOffset(ExtDexFile* ext_dex_file,
+                                     int64_t dex_offset,
+                                     /*out*/ ExtDexFileMethodInfo* method_info) {
+  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.
+  }
+
+  if (ext_dex_file->dex_file_->IsCompactDexFile()) {
+    // The data section of compact dex files might be shared.
+    // Check the subrange unique to this compact dex.
+    const art::CompactDexFile::Header& cdex_header =
+        ext_dex_file->dex_file_->AsCompactDexFile()->GetHeader();
+    uint32_t begin = cdex_header.data_off_ + cdex_header.OwnedDataBegin();
+    uint32_t end = cdex_header.data_off_ + cdex_header.OwnedDataEnd();
+    if (dex_offset < begin || dex_offset >= end) {
+      return false;  // The DEX offset is not within the bytecode of this dex file.
+    }
+  }
+
+  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->GetMethodName(*entry)};
+    return true;
+  }
+
+  return false;
+}
+
+void ExtDexFileGetAllMethodInfos(ExtDexFile* ext_dex_file,
+                                 int with_signature,
+                                 ExtDexFileMethodInfoCallback* method_info_cb,
+                                 void* user_data) {
+  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;
+      }
+
+      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); }
+
+}  // extern "C"
diff --git a/libdexfile/external/dex_file_supp.cc b/libdexfile/external/dex_file_supp.cc
new file mode 100644
index 0000000..6514c8a
--- /dev/null
+++ b/libdexfile/external/dex_file_supp.cc
@@ -0,0 +1,34 @@
+/*
+ * 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.
+ */
+
+#include "art_api/ext_dex_file.h"
+
+namespace art_api {
+namespace dex {
+
+DexFile::~DexFile() { ExtDexFileFree(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)};
+}
+
+void DexFile::AddMethodInfoCallback(const ExtDexFileMethodInfo* ext_method_info, void* ctx) {
+  auto vect = static_cast<MethodInfoVector*>(ctx);
+  vect->emplace_back(AbsorbMethodInfo(*ext_method_info));
+}
+
+}  // namespace dex
+}  // namespace art_api
diff --git a/libdexfile/external/include/art_api/ext_dex_file.h b/libdexfile/external/include/art_api/ext_dex_file.h
new file mode 100644
index 0000000..5f64ab1
--- /dev/null
+++ b/libdexfile/external/include/art_api/ext_dex_file.h
@@ -0,0 +1,248 @@
+/*
+ * 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_EXT_DEX_FILE_H_
+#define ART_LIBDEXFILE_EXTERNAL_INCLUDE_ART_API_EXT_DEX_FILE_H_
+
+// Dex file external API
+
+#include <sys/types.h>
+
+#include <cstring>
+#include <memory>
+#include <string>
+#include <string_view>
+#include <vector>
+
+#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,
+                                     /*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"
+
+namespace art_api {
+namespace dex {
+
+// Minimal std::string look-alike for a string returned from libdexfile.
+class DexString final {
+ public:
+  DexString(DexString&& dex_str) { ReplaceExtString(std::move(dex_str)); }
+  explicit DexString(const char* str = "") : ext_string_(ExtDexFileMakeString(str)) {}
+  ~DexString() { ExtDexFileFreeString(ext_string_); }
+
+  DexString& operator=(DexString&& dex_str) {
+    ReplaceExtString(std::move(dex_str));
+    return *this;
+  }
+
+  const char* data() const {
+    size_t ignored;
+    return ExtDexFileGetString(ext_string_, &ignored);
+  }
+  const char* c_str() const { return data(); }
+
+  size_t size() const {
+    size_t len;
+    (void)ExtDexFileGetString(ext_string_, &len);
+    return len;
+  }
+  size_t length() const { return size(); }
+
+  operator std::string_view() const {
+    size_t len;
+    const char* chars = ExtDexFileGetString(ext_string_, &len);
+    return std::string_view(chars, len);
+  }
+
+ private:
+  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.
+
+  void ReplaceExtString(DexString&& dex_str) {
+    ext_string_ = dex_str.ext_string_;
+    dex_str.ext_string_ = ExtDexFileMakeString("");
+  }
+
+  DISALLOW_COPY_AND_ASSIGN(DexString);
+};
+
+inline bool operator==(const DexString& s1, const DexString& s2) {
+  size_t l1, l2;
+  const char* str1 = ExtDexFileGetString(s1.ext_string_, &l1);
+  const char* str2 = 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);
+}
+
+struct MethodInfo {
+  int32_t offset;  // Code offset relative to the start of the dex file header
+  int32_t len;  // Code length
+  DexString name;
+};
+
+inline bool operator==(const MethodInfo& s1, const MethodInfo& s2) {
+  return s1.offset == s2.offset && s1.len == s2.len && s1.name == s2.name;
+}
+
+// External stable API to access ordinary dex files and CompactDex. This wraps
+// the stable C ABI and handles instance ownership. Thread-compatible but not
+// thread-safe.
+class DexFile {
+ public:
+  DexFile(DexFile&& dex_file) {
+    ext_dex_file_ = dex_file.ext_dex_file_;
+    dex_file.ext_dex_file_ = nullptr;
+  }
+  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
+  // 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
+  // path. It is mostly used to make error messages better, and may be "".
+  //
+  // The caller must retain the memory.
+  static std::unique_ptr<DexFile> OpenFromMemory(const void* addr,
+                                                 size_t* size,
+                                                 const std::string& location,
+                                                 /*out*/ std::string* error_msg) {
+    ExtDexFile* ext_dex_file;
+    const ExtDexFileString* ext_error_msg = nullptr;
+    if (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;
+  }
+
+  // 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.
+  //
+  // location is a string that describes the dex file, and is preferably its
+  // path. It is mostly used to make error messages better, and may be "".
+  static std::unique_ptr<DexFile> OpenFromFd(int fd,
+                                             off_t offset,
+                                             const std::string& location,
+                                             /*out*/ std::string* error_msg) {
+    ExtDexFile* ext_dex_file;
+    const ExtDexFileString* ext_error_msg = nullptr;
+    if (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;
+  }
+
+  // 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 GetMethodInfoForOffset(int64_t dex_offset) {
+    ExtDexFileMethodInfo ext_method_info;
+    if (ExtDexFileGetMethodInfoForOffset(ext_dex_file_, dex_offset, &ext_method_info)) {
+      return AbsorbMethodInfo(ext_method_info);
+    }
+    return {/*offset=*/0, /*len=*/0, /*name=*/DexString()};
+  }
+
+  // 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 = true) {
+    MethodInfoVector res;
+    ExtDexFileGetAllMethodInfos(
+        ext_dex_file_, with_signature, AddMethodInfoCallback, static_cast<void*>(&res));
+    return res;
+  }
+
+ private:
+  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);
+
+  DISALLOW_COPY_AND_ASSIGN(DexFile);
+};
+
+}  // namespace dex
+}  // namespace art_api
+
+#endif  // ART_LIBDEXFILE_EXTERNAL_INCLUDE_ART_API_EXT_DEX_FILE_H_
diff --git a/libdexfile/external/libdexfile_external.map.txt b/libdexfile/external/libdexfile_external.map.txt
new file mode 100644
index 0000000..450b633
--- /dev/null
+++ b/libdexfile/external/libdexfile_external.map.txt
@@ -0,0 +1,13 @@
+LIBDEXFILE_EXTERNAL_1 {
+  global:
+    ExtDexFileFree;
+    ExtDexFileFreeString;
+    ExtDexFileGetAllMethodInfos;
+    ExtDexFileGetMethodInfoForOffset;
+    ExtDexFileGetString;
+    ExtDexFileMakeString;
+    ExtDexFileOpenFromFd;
+    ExtDexFileOpenFromMemory;
+  local:
+    *;
+};
diff --git a/runtime/Android.bp b/runtime/Android.bp
index b03ef60..4780f16 100644
--- a/runtime/Android.bp
+++ b/runtime/Android.bp
@@ -420,6 +420,8 @@
         "libbacktrace",
         "libbase",
         "libcutils",
+        "libdexfile_external",  // libunwindstack dependency
+        "libdexfile_support",  // libunwindstack dependency
         "liblog",
         "libnativebridge",
         "libnativeloader",
@@ -553,9 +555,6 @@
     header_libs: [
         "libnativehelper_header_only",
     ],
-    include_dirs: [
-        "external/icu/icu4c/source/common",
-    ],
 }
 
 art_cc_test {
diff --git a/runtime/common_runtime_test.cc b/runtime/common_runtime_test.cc
index a101976..a20baa0 100644
--- a/runtime/common_runtime_test.cc
+++ b/runtime/common_runtime_test.cc
@@ -24,7 +24,6 @@
 #include "nativehelper/scoped_local_ref.h"
 
 #include "android-base/stringprintf.h"
-#include <unicode/uvernum.h>
 
 #include "art_field-inl.h"
 #include "base/file_utils.h"
diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc
index 77254ce..d47aca9 100644
--- a/runtime/gc/heap.cc
+++ b/runtime/gc/heap.cc
@@ -17,7 +17,9 @@
 #include "heap.h"
 
 #include <limits>
+#if defined(__BIONIC__) || defined(__GLIBC__)
 #include <malloc.h>  // For mallinfo()
+#endif
 #include <memory>
 #include <vector>
 
@@ -2622,8 +2624,8 @@
 
 size_t Heap::GetNativeBytes() {
   size_t malloc_bytes;
-  size_t mmapped_bytes;
 #if defined(__BIONIC__) || defined(__GLIBC__)
+  size_t mmapped_bytes;
   struct mallinfo mi = mallinfo();
   // In spite of the documentation, the jemalloc version of this call seems to do what we want,
   // and it is thread-safe.
diff --git a/runtime/gc/space/image_space.cc b/runtime/gc/space/image_space.cc
index 3f1d879..66db063 100644
--- a/runtime/gc/space/image_space.cc
+++ b/runtime/gc/space/image_space.cc
@@ -45,6 +45,7 @@
 #include "dex/dex_file_loader.h"
 #include "exec_utils.h"
 #include "gc/accounting/space_bitmap-inl.h"
+#include "gc/task_processor.h"
 #include "image-inl.h"
 #include "image_space_fs.h"
 #include "intern_table-inl.h"
@@ -684,30 +685,39 @@
       REQUIRES_SHARED(Locks::mutator_lock_) {
     TimingLogger logger(__PRETTY_FUNCTION__, /*precise=*/ true, VLOG_IS_ON(image));
 
-    const bool create_thread_pool = true;
     std::unique_ptr<ThreadPool> thread_pool;
-    if (create_thread_pool) {
-      TimingLogger::ScopedTiming timing("CreateThreadPool", &logger);
-      ScopedThreadStateChange stsc(Thread::Current(), kNative);
-      constexpr size_t kStackSize = 64 * KB;
-      constexpr size_t kMaxRuntimeWorkers = 4u;
-      const size_t num_workers =
-          std::min(static_cast<size_t>(std::thread::hardware_concurrency()), kMaxRuntimeWorkers);
-      thread_pool.reset(new ThreadPool("Runtime", num_workers, /*create_peers=*/false, kStackSize));
-      thread_pool->StartWorkers(Thread::Current());
-    }
-
     std::unique_ptr<ImageSpace> space = Init(image_filename,
                                              image_location,
                                              oat_file,
                                              &logger,
-                                             thread_pool.get(),
+                                             &thread_pool,
                                              image_reservation,
                                              error_msg);
     if (thread_pool != nullptr) {
-      TimingLogger::ScopedTiming timing("CreateThreadPool", &logger);
-      ScopedThreadStateChange stsc(Thread::Current(), kNative);
-      thread_pool.reset();
+      // Delay the thread pool deletion to prevent the deletion slowing down the startup by causing
+      // preemption. TODO: Just do this in heap trim.
+      static constexpr uint64_t kThreadPoolDeleteDelay = MsToNs(5000);
+
+      class DeleteThreadPoolTask : public HeapTask {
+       public:
+        explicit DeleteThreadPoolTask(std::unique_ptr<ThreadPool>&& thread_pool)
+            : HeapTask(NanoTime() + kThreadPoolDeleteDelay), thread_pool_(std::move(thread_pool)) {}
+
+        void Run(Thread* self) override {
+          ScopedTrace trace("DestroyThreadPool");
+          ScopedThreadStateChange stsc(self, kNative);
+          thread_pool_.reset();
+        }
+
+       private:
+        std::unique_ptr<ThreadPool> thread_pool_;
+      };
+      gc::TaskProcessor* const processor = Runtime::Current()->GetHeap()->GetTaskProcessor();
+      // The thread pool is already done being used since Init has finished running. Deleting the
+      // thread pool is done async since it takes a non-trivial amount of time to do.
+      if (processor != nullptr) {
+        processor->AddTask(Thread::Current(), new DeleteThreadPoolTask(std::move(thread_pool)));
+      }
     }
     if (space != nullptr) {
       uint32_t expected_reservation_size =
@@ -769,7 +779,7 @@
                                           const char* image_location,
                                           const OatFile* oat_file,
                                           TimingLogger* logger,
-                                          ThreadPool* thread_pool,
+                                          std::unique_ptr<ThreadPool>* thread_pool,
                                           /*inout*/MemMap* image_reservation,
                                           /*out*/std::string* error_msg)
       REQUIRES_SHARED(Locks::mutator_lock_) {
@@ -846,6 +856,18 @@
       return nullptr;
     }
 
+    const size_t kMinBlocks = 2;
+    if (thread_pool != nullptr && image_header->GetBlockCount() >= kMinBlocks) {
+      TimingLogger::ScopedTiming timing("CreateThreadPool", logger);
+      ScopedThreadStateChange stsc(Thread::Current(), kNative);
+      constexpr size_t kStackSize = 64 * KB;
+      constexpr size_t kMaxRuntimeWorkers = 4u;
+      const size_t num_workers =
+          std::min(static_cast<size_t>(std::thread::hardware_concurrency()), kMaxRuntimeWorkers);
+      thread_pool->reset(new ThreadPool("Image", num_workers, /*create_peers=*/false, kStackSize));
+      thread_pool->get()->StartWorkers(Thread::Current());
+    }
+
     // GetImageBegin is the preferred address to map the image. If we manage to map the
     // image at the image begin, the amount of fixup work required is minimized.
     // If it is pic we will retry with error_msg for the failure case. Pass a null error_msg to
@@ -858,7 +880,7 @@
         *image_header,
         file->Fd(),
         logger,
-        thread_pool,
+        thread_pool != nullptr ? thread_pool->get() : nullptr,
         image_reservation,
         error_msg);
     if (!map.IsValid()) {
@@ -995,8 +1017,7 @@
 
       const uint64_t start = NanoTime();
       Thread* const self = Thread::Current();
-      const size_t kMinBlocks = 2;
-      const bool use_parallel = pool != nullptr && image_header.GetBlockCount() >= kMinBlocks;
+      const bool use_parallel = pool != nullptr;
       for (const ImageHeader::Block& block : image_header.GetBlocks(temp_map.Begin())) {
         auto function = [&](Thread*) {
           const uint64_t start2 = NanoTime();
diff --git a/runtime/jit/jit.cc b/runtime/jit/jit.cc
index 43f32b9..03c97f4 100644
--- a/runtime/jit/jit.cc
+++ b/runtime/jit/jit.cc
@@ -291,6 +291,12 @@
   return success;
 }
 
+void Jit::WaitForWorkersToBeCreated() {
+  if (thread_pool_ != nullptr) {
+    thread_pool_->WaitForWorkersToBeCreated();
+  }
+}
+
 void Jit::DeleteThreadPool() {
   Thread* self = Thread::Current();
   DCHECK(Runtime::Current()->IsShuttingDown(self));
diff --git a/runtime/jit/jit.h b/runtime/jit/jit.h
index 485537c..e5c9766 100644
--- a/runtime/jit/jit.h
+++ b/runtime/jit/jit.h
@@ -174,6 +174,7 @@
 
   void CreateThreadPool();
   void DeleteThreadPool();
+  void WaitForWorkersToBeCreated();
 
   // Dump interesting info: #methods compiled, code vs data size, compile / verify cumulative
   // loggers.
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index c5a8a23..55bc2ec 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -349,6 +349,9 @@
   }
 
   if (jit_ != nullptr) {
+    // Wait for the workers to be created since there can't be any threads attaching during
+    // shutdown.
+    jit_->WaitForWorkersToBeCreated();
     // Stop the profile saver thread before marking the runtime as shutting down.
     // The saver will try to dump the profiles before being sopped and that
     // requires holding the mutator lock.
diff --git a/runtime/thread_pool.cc b/runtime/thread_pool.cc
index de698c2..e1c756d 100644
--- a/runtime/thread_pool.cc
+++ b/runtime/thread_pool.cc
@@ -1,3 +1,4 @@
+
 /*
  * Copyright (C) 2012 The Android Open Source Project
  *
@@ -86,7 +87,7 @@
 void ThreadPoolWorker::Run() {
   Thread* self = Thread::Current();
   Task* task = nullptr;
-  thread_pool_->creation_barier_.Wait(self);
+  thread_pool_->creation_barier_.Pass(self);
   while ((task = thread_pool_->GetTask(self)) != nullptr) {
     task->Run(self);
     task->Finalize();
@@ -150,7 +151,7 @@
     MutexLock mu(self, task_queue_lock_);
     shutting_down_ = false;
     // Add one since the caller of constructor waits on the barrier too.
-    creation_barier_.Init(self, max_active_workers_ + 1);
+    creation_barier_.Init(self, max_active_workers_);
     while (GetThreadCount() < max_active_workers_) {
       const std::string worker_name = StringPrintf("%s worker thread %zu", name_.c_str(),
                                                    GetThreadCount());
@@ -158,8 +159,16 @@
           new ThreadPoolWorker(this, worker_name, worker_stack_size_));
     }
   }
-  // Wait for all of the threads to attach.
-  creation_barier_.Wait(Thread::Current());
+}
+
+void ThreadPool::WaitForWorkersToBeCreated() {
+  creation_barier_.Increment(Thread::Current(), 0);
+}
+
+const std::vector<ThreadPoolWorker*>& ThreadPool::GetWorkers() {
+  // Wait for all the workers to be created before returning them.
+  WaitForWorkersToBeCreated();
+  return threads_;
 }
 
 void ThreadPool::DeleteThreads() {
diff --git a/runtime/thread_pool.h b/runtime/thread_pool.h
index f55d72e..0a2a50c 100644
--- a/runtime/thread_pool.h
+++ b/runtime/thread_pool.h
@@ -101,9 +101,7 @@
     return threads_.size();
   }
 
-  const std::vector<ThreadPoolWorker*>& GetWorkers() const {
-    return threads_;
-  }
+  const std::vector<ThreadPoolWorker*>& GetWorkers();
 
   // Broadcast to the workers and tell them to empty out the work queue.
   void StartWorkers(Thread* self) REQUIRES(!task_queue_lock_);
@@ -154,6 +152,9 @@
   // Set the "nice" priorty for threads in the pool.
   void SetPthreadPriority(int priority);
 
+  // Wait for workers to be created.
+  void WaitForWorkersToBeCreated();
+
  protected:
   // get a task to run, blocks if there are no tasks left
   virtual Task* GetTask(Thread* self) REQUIRES(!task_queue_lock_);
diff --git a/test/Android.run-test.mk b/test/Android.run-test.mk
index 5d07601..e3157ef 100644
--- a/test/Android.run-test.mk
+++ b/test/Android.run-test.mk
@@ -47,12 +47,8 @@
 # Also need libopenjdkjvmti.
 ART_TEST_TARGET_RUN_TEST_DEPENDENCIES += libopenjdkjvmti-target libopenjdkjvmtid-target
 
-ART_TEST_TARGET_RUN_TEST_DEPENDENCIES += $(TARGET_OUT_JAVA_LIBRARIES)/core-libart-testdex.jar
-ART_TEST_TARGET_RUN_TEST_DEPENDENCIES += $(TARGET_OUT_JAVA_LIBRARIES)/core-oj-testdex.jar
-ART_TEST_TARGET_RUN_TEST_DEPENDENCIES += $(TARGET_OUT_JAVA_LIBRARIES)/core-simple-testdex.jar
-ART_TEST_TARGET_RUN_TEST_DEPENDENCIES += $(TARGET_OUT_JAVA_LIBRARIES)/conscrypt-testdex.jar
-ART_TEST_TARGET_RUN_TEST_DEPENDENCIES += $(TARGET_OUT_JAVA_LIBRARIES)/okhttp-testdex.jar
-ART_TEST_TARGET_RUN_TEST_DEPENDENCIES += $(TARGET_OUT_JAVA_LIBRARIES)/bouncycastle-testdex.jar
+ART_TEST_TARGET_RUN_TEST_DEPENDENCIES += \
+  $(foreach jar,$(TARGET_TEST_CORE_JARS),$(TARGET_OUT_JAVA_LIBRARIES)/$(jar).jar)
 
 # All tests require the host executables. The tests also depend on the core images, but on
 # specific version depending on the compiler.
@@ -74,6 +70,7 @@
   $(ART_HOST_OUT_SHARED_LIBRARIES)/libopenjdkd$(ART_HOST_SHLIB_EXTENSION) \
   $(ART_HOST_OUT_SHARED_LIBRARIES)/libopenjdkjvmti$(ART_HOST_SHLIB_EXTENSION) \
   $(ART_HOST_OUT_SHARED_LIBRARIES)/libopenjdkjvmtid$(ART_HOST_SHLIB_EXTENSION) \
+  $(HOST_CORE_DEX_LOCATIONS) \
 
 ifneq ($(HOST_PREFER_32_BIT),true)
 ART_TEST_HOST_RUN_TEST_DEPENDENCIES += \
diff --git a/test/knownfailures.json b/test/knownfailures.json
index ae20557..a723c3b 100644
--- a/test/knownfailures.json
+++ b/test/knownfailures.json
@@ -569,6 +569,12 @@
         "env_vars": {"SANITIZE_HOST": "address"}
     },
     {
+        "tests": "175-alloc-big-bignums",
+        "description": "ASAN runs out of memory due to huge allocations.",
+        "variant": "host",
+        "env_vars": {"SANITIZE_HOST": "address"}
+    },
+    {
         "tests": "202-thread-oome",
         "description": "ASAN aborts when large thread stacks are requested.",
         "variant": "host",