Merge changes from topic "dexfile-hooks"

* changes:
  Add minimal libdexfile API for external users.
  Plumb through the container as an optional arg to DexFileLoader::Open.
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.common_path.mk b/build/Android.common_path.mk
index 1880726..03e68ae 100644
--- a/build/Android.common_path.mk
+++ b/build/Android.common_path.mk
@@ -73,21 +73,8 @@
 HOST_CORE_IMG_LOCATION := $(HOST_OUT_JAVA_LIBRARIES)/core.art
 TARGET_CORE_IMG_LOCATION := $(ART_TARGET_TEST_OUT)/core.art
 
-# Modules to compile for core.art.
-CORE_IMG_JARS := core-oj core-libart core-simple okhttp bouncycastle
-HOST_CORE_IMG_JARS   := $(addsuffix -hostdex,$(CORE_IMG_JARS))
-TARGET_CORE_IMG_JARS := $(addsuffix -testdex,$(CORE_IMG_JARS))
-HOST_CORE_IMG_DEX_LOCATIONS   := $(foreach jar,$(HOST_CORE_IMG_JARS),  $(HOST_OUT_JAVA_LIBRARIES)/$(jar).jar)
-ifeq ($(ART_TEST_ANDROID_ROOT),)
-TARGET_CORE_IMG_DEX_LOCATIONS := $(foreach jar,$(TARGET_CORE_IMG_JARS),/$(DEXPREOPT_BOOT_JAR_DIR)/$(jar).jar)
-else
-TARGET_CORE_IMG_DEX_LOCATIONS := $(foreach jar,$(TARGET_CORE_IMG_JARS),$(ART_TEST_ANDROID_ROOT)/$(jar).jar)
-endif
-HOST_CORE_IMG_DEX_FILES   := $(foreach jar,$(HOST_CORE_IMG_JARS),  $(call intermediates-dir-for,JAVA_LIBRARIES,$(jar),t,COMMON)/javalib.jar)
-TARGET_CORE_IMG_DEX_FILES := $(foreach jar,$(TARGET_CORE_IMG_JARS),$(call intermediates-dir-for,JAVA_LIBRARIES,$(jar), ,COMMON)/javalib.jar)
-
-# Jar files for the boot class path for testing. Must start with CORE_IMG_JARS.
-TEST_CORE_JARS := $(CORE_IMG_JARS) conscrypt
+# Jar files for core.art.
+TEST_CORE_JARS := core-oj core-libart core-simple conscrypt okhttp bouncycastle
 HOST_TEST_CORE_JARS   := $(addsuffix -hostdex,$(TEST_CORE_JARS))
 TARGET_TEST_CORE_JARS := $(addsuffix -testdex,$(TEST_CORE_JARS))
 HOST_CORE_DEX_LOCATIONS   := $(foreach jar,$(HOST_TEST_CORE_JARS),  $(HOST_OUT_JAVA_LIBRARIES)/$(jar).jar)
@@ -96,6 +83,7 @@
 else
 TARGET_CORE_DEX_LOCATIONS := $(foreach jar,$(TARGET_TEST_CORE_JARS),$(ART_TEST_ANDROID_ROOT)/framework/$(jar).jar)
 endif
+
 HOST_CORE_DEX_FILES   := $(foreach jar,$(HOST_TEST_CORE_JARS),  $(call intermediates-dir-for,JAVA_LIBRARIES,$(jar),t,COMMON)/javalib.jar)
 TARGET_CORE_DEX_FILES := $(foreach jar,$(TARGET_TEST_CORE_JARS),$(call intermediates-dir-for,JAVA_LIBRARIES,$(jar), ,COMMON)/javalib.jar)
 
diff --git a/build/Android.gtest.mk b/build/Android.gtest.mk
index 468eec6..11ebc2f 100644
--- a/build/Android.gtest.mk
+++ b/build/Android.gtest.mk
@@ -543,7 +543,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/build/Android.oat.mk b/build/Android.oat.mk
index 2ad1143..e2adac1 100644
--- a/build/Android.oat.mk
+++ b/build/Android.oat.mk
@@ -39,6 +39,8 @@
 # Use dex2oat debug version for better error reporting
 # $(1): compiler - optimizing, interpreter or interp-ac (interpreter-access-checks).
 # $(2): 2ND_ or undefined, 2ND_ for 32-bit host builds.
+# NB depending on HOST_CORE_DEX_LOCATIONS so we are sure to have the dex files in frameworks for
+# run-test --no-image
 define create-core-oat-host-rules
   core_compile_options :=
   core_image_name :=
@@ -78,15 +80,13 @@
 $$(core_image_name): PRIVATE_CORE_COMPILE_OPTIONS := $$(core_compile_options)
 $$(core_image_name): PRIVATE_CORE_IMG_NAME := $$(core_image_name)
 $$(core_image_name): PRIVATE_CORE_OAT_NAME := $$(core_oat_name)
-$$(core_image_name): $$(HOST_CORE_IMG_DEX_LOCATIONS) $$(core_dex2oat_dependency)
+$$(core_image_name): $$(HOST_CORE_DEX_LOCATIONS) $$(core_dex2oat_dependency)
 	@echo "host dex2oat: $$@"
 	@mkdir -p $$(dir $$@)
 	$$(hide) ANDROID_LOG_TAGS="*:e" $$(DEX2OAT) --runtime-arg -Xms$(DEX2OAT_IMAGE_XMS) \
 	  --runtime-arg -Xmx$(DEX2OAT_IMAGE_XMX) \
-	  --image-classes=$$(PRELOADED_CLASSES) \
-	  $$(addprefix --dex-file=,$$(HOST_CORE_IMG_DEX_FILES)) \
-	  $$(addprefix --dex-location=,$$(HOST_CORE_IMG_DEX_LOCATIONS)) \
-	  --oat-file=$$(PRIVATE_CORE_OAT_NAME) \
+	  --image-classes=$$(PRELOADED_CLASSES) $$(addprefix --dex-file=,$$(HOST_CORE_DEX_FILES)) \
+	  $$(addprefix --dex-location=,$$(HOST_CORE_DEX_LOCATIONS)) --oat-file=$$(PRIVATE_CORE_OAT_NAME) \
 	  --oat-location=$$(PRIVATE_CORE_OAT_NAME) --image=$$(PRIVATE_CORE_IMG_NAME) \
 	  --base=$$(LIBART_IMG_HOST_BASE_ADDRESS) --instruction-set=$$($(2)ART_HOST_ARCH) \
 	  $$(LOCAL_$(2)DEX2OAT_HOST_INSTRUCTION_SET_FEATURES_OPTION) \
@@ -169,15 +169,13 @@
 $$(core_image_name): PRIVATE_CORE_COMPILE_OPTIONS := $$(core_compile_options)
 $$(core_image_name): PRIVATE_CORE_IMG_NAME := $$(core_image_name)
 $$(core_image_name): PRIVATE_CORE_OAT_NAME := $$(core_oat_name)
-$$(core_image_name): $$(TARGET_CORE_IMG_DEX_FILES) $$(core_dex2oat_dependency)
+$$(core_image_name): $$(TARGET_CORE_DEX_FILES) $$(core_dex2oat_dependency)
 	@echo "target dex2oat: $$@"
 	@mkdir -p $$(dir $$@)
 	$$(hide) $$(DEX2OAT) --runtime-arg -Xms$(DEX2OAT_IMAGE_XMS) \
 	  --runtime-arg -Xmx$(DEX2OAT_IMAGE_XMX) \
-	  --image-classes=$$(PRELOADED_CLASSES) \
-	  $$(addprefix --dex-file=,$$(TARGET_CORE_IMG_DEX_FILES)) \
-	  $$(addprefix --dex-location=,$$(TARGET_CORE_IMG_DEX_LOCATIONS)) \
-	  --oat-file=$$(PRIVATE_CORE_OAT_NAME) \
+	  --image-classes=$$(PRELOADED_CLASSES) $$(addprefix --dex-file=,$$(TARGET_CORE_DEX_FILES)) \
+	  $$(addprefix --dex-location=,$$(TARGET_CORE_DEX_LOCATIONS)) --oat-file=$$(PRIVATE_CORE_OAT_NAME) \
 	  --oat-location=$$(PRIVATE_CORE_OAT_NAME) --image=$$(PRIVATE_CORE_IMG_NAME) \
 	  --base=$$(LIBART_IMG_TARGET_BASE_ADDRESS) --instruction-set=$$($(2)TARGET_ARCH) \
 	  --instruction-set-variant=$$($(2)DEX2OAT_TARGET_CPU_VARIANT) \
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index 872fab3..a5bba9b 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -624,6 +624,7 @@
   explicit Dex2Oat(TimingLogger* timings) :
       compiler_kind_(Compiler::kOptimizing),
       // Take the default set of instruction features from the build.
+      boot_image_checksum_(0),
       key_value_store_(nullptr),
       verification_results_(nullptr),
       runtime_(nullptr),
@@ -1436,22 +1437,17 @@
 
     if (!IsBootImage()) {
       // When compiling an app, create the runtime early to retrieve
-      // the boot image checksums needed for the oat header.
+      // the image location key needed for the oat header.
       if (!CreateRuntime(std::move(runtime_options))) {
         return dex2oat::ReturnCode::kCreateRuntime;
       }
 
       if (CompilerFilter::DependsOnImageChecksum(compiler_options_->GetCompilerFilter())) {
         TimingLogger::ScopedTiming t3("Loading image checksum", timings_);
-        Runtime* runtime = Runtime::Current();
-        key_value_store_->Put(OatHeader::kBootClassPathKey,
-                              android::base::Join(runtime->GetBootClassPathLocations(), ':'));
-        std::vector<ImageSpace*> image_spaces = runtime->GetHeap()->GetBootImageSpaces();
-        const std::vector<const DexFile*>& bcp_dex_files =
-            runtime->GetClassLinker()->GetBootClassPath();
-        key_value_store_->Put(
-            OatHeader::kBootClassPathChecksumsKey,
-            gc::space::ImageSpace::GetBootClassPathChecksums(image_spaces, bcp_dex_files));
+        std::vector<ImageSpace*> image_spaces = Runtime::Current()->GetHeap()->GetBootImageSpaces();
+        boot_image_checksum_ = image_spaces[0]->GetImageHeader().GetImageChecksum();
+      } else {
+        boot_image_checksum_ = 0u;
       }
 
       // Open dex files for class path.
@@ -2019,7 +2015,7 @@
           elf_writer->EndDataBimgRelRo(data_bimg_rel_ro);
         }
 
-        if (!oat_writer->WriteHeader(elf_writer->GetStream())) {
+        if (!oat_writer->WriteHeader(elf_writer->GetStream(), boot_image_checksum_)) {
           LOG(ERROR) << "Failed to write oat header to the ELF file " << oat_file->GetPath();
           return false;
         }
@@ -2650,6 +2646,7 @@
   std::unique_ptr<CompilerOptions> compiler_options_;
   Compiler::Kind compiler_kind_;
 
+  uint32_t boot_image_checksum_;
   std::unique_ptr<SafeMap<std::string, std::string> > key_value_store_;
 
   std::unique_ptr<VerificationResults> verification_results_;
diff --git a/dex2oat/linker/image_test.h b/dex2oat/linker/image_test.h
index fa0a3d4..bd8cf5a 100644
--- a/dex2oat/linker/image_test.h
+++ b/dex2oat/linker/image_test.h
@@ -326,7 +326,8 @@
           elf_writer->EndDataBimgRelRo(data_bimg_rel_ro);
         }
 
-        bool header_ok = oat_writer->WriteHeader(elf_writer->GetStream());
+        bool header_ok = oat_writer->WriteHeader(elf_writer->GetStream(),
+                                                 /*boot_image_checksum=*/ 0u);
         ASSERT_TRUE(header_ok);
 
         writer->UpdateOatFileHeader(i, oat_writer->GetOatHeader());
diff --git a/dex2oat/linker/image_writer.cc b/dex2oat/linker/image_writer.cc
index e4e4b13..61d105f 100644
--- a/dex2oat/linker/image_writer.cc
+++ b/dex2oat/linker/image_writer.cc
@@ -32,7 +32,6 @@
 #include "base/enums.h"
 #include "base/globals.h"
 #include "base/logging.h"  // For VLOG.
-#include "base/stl_util.h"
 #include "base/unix_file/fd_file.h"
 #include "class_linker-inl.h"
 #include "class_root.h"
@@ -154,26 +153,6 @@
       : nullptr;
 }
 
-bool ImageWriter::IsImageObject(ObjPtr<mirror::Object> obj) const {
-  // For boot image, we keep all objects remaining after the GC in PrepareImageAddressSpace().
-  if (compiler_options_.IsBootImage()) {
-    return true;
-  }
-  // Objects already in the boot image do not belong to the image being written.
-  if (IsInBootImage(obj.Ptr())) {
-    return false;
-  }
-  // DexCaches for the boot class path components that are not a part of the boot image
-  // cannot be garbage collected in PrepareImageAddressSpace() but we do not want to
-  // include them in the app image. So make sure we include only the app DexCaches.
-  if (obj->IsDexCache() &&
-      !ContainsElement(compiler_options_.GetDexFilesForOatFile(),
-                       obj->AsDexCache()->GetDexFile())) {
-    return false;
-  }
-  return true;
-}
-
 // Return true if an object is already in an image space.
 bool ImageWriter::IsInBootImage(const void* obj) const {
   gc::Heap* const heap = Runtime::Current()->GetHeap();
@@ -458,7 +437,7 @@
    */
   heap->VisitObjects([this, &visitor](ObjPtr<mirror::Object> object)
       REQUIRES_SHARED(Locks::mutator_lock_) {
-    if (IsImageObject(object)) {
+    if (!IsInBootImage(object.Ptr())) {
       visitor.SetObject(object);
 
       if (object->IsDexCache()) {
@@ -701,7 +680,7 @@
     ObjPtr<mirror::ClassLoader> class_loader = GetAppClassLoader();
     std::vector<ObjPtr<mirror::DexCache>> dex_caches = FindDexCaches(self);
     for (ObjPtr<mirror::DexCache> dex_cache : dex_caches) {
-      if (!IsImageObject(dex_cache)) {
+      if (IsInBootImage(dex_cache.Ptr())) {
         continue;  // Boot image DexCache is not written to the app image.
       }
       PreloadDexCache(dex_cache, class_loader);
@@ -1010,7 +989,7 @@
   for (const ClassLinker::DexCacheData& data : class_linker->GetDexCachesData()) {
     ObjPtr<mirror::DexCache> dex_cache =
         ObjPtr<mirror::DexCache>::DownCast(self->DecodeJObject(data.weak_root));
-    if (dex_cache == nullptr || !IsImageObject(dex_cache)) {
+    if (dex_cache == nullptr || IsInBootImage(dex_cache.Ptr())) {
       continue;
     }
     const DexFile* dex_file = dex_cache->GetDexFile();
@@ -1779,8 +1758,7 @@
   for (ObjPtr<mirror::DexCache> dex_cache : dex_caches) {
     // Pass the class loader associated with the DexCache. This can either be
     // the app's `class_loader` or `nullptr` if boot class loader.
-    bool is_app_image_dex_cache = compiler_options_.IsAppImage() && IsImageObject(dex_cache);
-    PruneDexCache(dex_cache, is_app_image_dex_cache ? GetAppClassLoader() : nullptr);
+    PruneDexCache(dex_cache, IsInBootImage(dex_cache.Ptr()) ? nullptr : GetAppClassLoader());
   }
 
   // Drop the array class cache in the ClassLinker, as these are roots holding those classes live.
@@ -1878,7 +1856,7 @@
         continue;
       }
       const DexFile* dex_file = dex_cache->GetDexFile();
-      if (IsImageObject(dex_cache)) {
+      if (!IsInBootImage(dex_cache.Ptr())) {
         dex_cache_count += image_dex_files.find(dex_file) != image_dex_files.end() ? 1u : 0u;
       }
     }
@@ -1897,7 +1875,7 @@
         continue;
       }
       const DexFile* dex_file = dex_cache->GetDexFile();
-      if (IsImageObject(dex_cache)) {
+      if (!IsInBootImage(dex_cache.Ptr())) {
         non_image_dex_caches += image_dex_files.find(dex_file) != image_dex_files.end() ? 1u : 0u;
       }
     }
@@ -1911,7 +1889,7 @@
         continue;
       }
       const DexFile* dex_file = dex_cache->GetDexFile();
-      if (IsImageObject(dex_cache) &&
+      if (!IsInBootImage(dex_cache.Ptr()) &&
           image_dex_files.find(dex_file) != image_dex_files.end()) {
         dex_caches->Set<false>(i, dex_cache.Ptr());
         ++i;
@@ -1964,7 +1942,7 @@
 mirror::Object* ImageWriter::TryAssignBinSlot(WorkStack& work_stack,
                                               mirror::Object* obj,
                                               size_t oat_index) {
-  if (obj == nullptr || !IsImageObject(obj)) {
+  if (obj == nullptr || IsInBootImage(obj)) {
     // Object is null or already in the image, there is no work to do.
     return obj;
   }
@@ -2395,7 +2373,7 @@
   {
     auto ensure_bin_slots_assigned = [&](mirror::Object* obj)
         REQUIRES_SHARED(Locks::mutator_lock_) {
-      if (IsImageObject(obj)) {
+      if (!Runtime::Current()->GetHeap()->ObjectIsInBootImageSpace(obj)) {
         CHECK(IsImageBinSlotAssigned(obj)) << mirror::Object::PrettyTypeOf(obj) << " " << obj;
       }
     };
@@ -2466,7 +2444,7 @@
   {
     auto unbin_objects_into_offset = [&](mirror::Object* obj)
         REQUIRES_SHARED(Locks::mutator_lock_) {
-      if (IsImageObject(obj)) {
+      if (!IsInBootImage(obj)) {
         UnbinObjectsIntoOffset(obj);
       }
     };
@@ -2931,7 +2909,7 @@
 }
 
 void ImageWriter::CopyAndFixupObject(Object* obj) {
-  if (!IsImageObject(obj)) {
+  if (IsInBootImage(obj)) {
     return;
   }
   size_t offset = GetImageOffset(obj);
diff --git a/dex2oat/linker/image_writer.h b/dex2oat/linker/image_writer.h
index b680265..33bacf8 100644
--- a/dex2oat/linker/image_writer.h
+++ b/dex2oat/linker/image_writer.h
@@ -674,12 +674,7 @@
   template <typename T>
   T* NativeCopyLocation(T* obj) REQUIRES_SHARED(Locks::mutator_lock_);
 
-  // Return true if `obj` belongs to the image we're writing.
-  // For a boot image, this is true for all objects.
-  // For an app image, boot image objects and boot class path dex caches are excluded.
-  bool IsImageObject(ObjPtr<mirror::Object> obj) const REQUIRES_SHARED(Locks::mutator_lock_);
-
-  // Return true if `obj` is inside of the boot image space. This may only return true if we are
+  // Return true of obj is inside of the boot image space. This may only return true if we are
   // compiling an app image.
   bool IsInBootImage(const void* obj) const;
 
diff --git a/dex2oat/linker/oat_writer.cc b/dex2oat/linker/oat_writer.cc
index e2a9ac2..d045698 100644
--- a/dex2oat/linker/oat_writer.cc
+++ b/dex2oat/linker/oat_writer.cc
@@ -2808,9 +2808,11 @@
   return true;
 }
 
-bool OatWriter::WriteHeader(OutputStream* out) {
+bool OatWriter::WriteHeader(OutputStream* out, uint32_t boot_image_checksum) {
   CHECK(write_state_ == WriteState::kWriteHeader);
 
+  oat_header_->SetBootImageChecksum(boot_image_checksum);
+
   // Update checksum with header data.
   DCHECK_EQ(oat_header_->GetChecksum(), 0u);  // For checksum calculation.
   const uint8_t* header_begin = reinterpret_cast<const uint8_t*>(oat_header_.get());
diff --git a/dex2oat/linker/oat_writer.h b/dex2oat/linker/oat_writer.h
index cc0e83a..9cd2fd0 100644
--- a/dex2oat/linker/oat_writer.h
+++ b/dex2oat/linker/oat_writer.h
@@ -198,7 +198,7 @@
   // Check the size of the written oat file.
   bool CheckOatSize(OutputStream* out, size_t file_offset, size_t relative_offset);
   // Write the oat header. This finalizes the oat file.
-  bool WriteHeader(OutputStream* out);
+  bool WriteHeader(OutputStream* out, uint32_t boot_image_checksum);
 
   // Returns whether the oat file has an associated image.
   bool HasImage() const {
diff --git a/dex2oat/linker/oat_writer_test.cc b/dex2oat/linker/oat_writer_test.cc
index ecf9db8..5de1540 100644
--- a/dex2oat/linker/oat_writer_test.cc
+++ b/dex2oat/linker/oat_writer_test.cc
@@ -240,7 +240,7 @@
       elf_writer->EndDataBimgRelRo(data_bimg_rel_ro);
     }
 
-    if (!oat_writer.WriteHeader(elf_writer->GetStream())) {
+    if (!oat_writer.WriteHeader(elf_writer->GetStream(), /*boot_image_checksum=*/ 42u)) {
       return false;
     }
 
@@ -396,7 +396,6 @@
 
   ScratchFile tmp_base, tmp_oat(tmp_base, ".oat"), tmp_vdex(tmp_base, ".vdex");
   SafeMap<std::string, std::string> key_value_store;
-  key_value_store.Put(OatHeader::kBootClassPathChecksumsKey, "testkey");
   bool success = WriteElf(tmp_vdex.GetFile(),
                           tmp_oat.GetFile(),
                           class_linker->GetBootClassPath(),
@@ -419,8 +418,7 @@
   const OatHeader& oat_header = oat_file->GetOatHeader();
   ASSERT_TRUE(oat_header.IsValid());
   ASSERT_EQ(class_linker->GetBootClassPath().size(), oat_header.GetDexFileCount());  // core
-  ASSERT_TRUE(oat_header.GetStoreValueByKey(OatHeader::kBootClassPathChecksumsKey) != nullptr);
-  ASSERT_STREQ("testkey", oat_header.GetStoreValueByKey(OatHeader::kBootClassPathChecksumsKey));
+  ASSERT_EQ(42u, oat_header.GetBootImageChecksum());
 
   ASSERT_TRUE(java_lang_dex_file_ != nullptr);
   const DexFile& dex_file = *java_lang_dex_file_;
@@ -466,7 +464,7 @@
 TEST_F(OatTest, OatHeaderSizeCheck) {
   // If this test is failing and you have to update these constants,
   // it is time to update OatHeader::kOatVersion
-  EXPECT_EQ(64U, sizeof(OatHeader));
+  EXPECT_EQ(68U, sizeof(OatHeader));
   EXPECT_EQ(4U, sizeof(OatMethodOffsets));
   EXPECT_EQ(8U, sizeof(OatQuickMethodHeader));
   EXPECT_EQ(166 * static_cast<size_t>(GetInstructionSetPointerSize(kRuntimeISA)),
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..f292303 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"
@@ -329,18 +328,15 @@
 }
 
 std::vector<std::string> CommonArtTestImpl::GetLibCoreDexFileNames() {
-  // Note: This must start with the CORE_IMG_JARS in Android.common_path.mk
+  // Note: This must match the TEST_CORE_JARS in Android.common_path.mk
   // because that's what we use for compiling the core.art image.
-  // It may contain additional modules from TEST_CORE_JARS.
   static const char* const kLibcoreModules[] = {
-      // CORE_IMG_JARS modules.
       "core-oj",
       "core-libart",
       "core-simple",
+      "conscrypt",
       "okhttp",
       "bouncycastle",
-      // Additional modules.
-      "conscrypt",
   };
 
   std::vector<std::string> result;
diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc
index d2a5bb8..1c74a92 100644
--- a/oatdump/oatdump.cc
+++ b/oatdump/oatdump.cc
@@ -473,6 +473,9 @@
                            GetQuickToInterpreterBridgeOffset);
 #undef DUMP_OAT_HEADER_OFFSET
 
+    os << "BOOT IMAGE CHECKSUM:\n";
+    os << StringPrintf("0x%08x\n\n", oat_header.GetBootImageChecksum());
+
     // Print the key-value store.
     {
       os << "KEY VALUE STORE:\n";
diff --git a/runtime/Android.bp b/runtime/Android.bp
index 211fb88..4780f16 100644
--- a/runtime/Android.bp
+++ b/runtime/Android.bp
@@ -555,9 +555,6 @@
     header_libs: [
         "libnativehelper_header_only",
     ],
-    include_dirs: [
-        "external/icu/icu4c/source/common",
-    ],
 }
 
 art_cc_test {
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index f6a3e32..d33541c 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -1037,15 +1037,20 @@
   runtime->SetSentinel(heap->AllocNonMovableObject<true>(
       self, java_lang_Object, java_lang_Object->GetObjectSize(), VoidFunctor()));
 
-  const std::vector<std::string>& boot_class_path_locations = runtime->GetBootClassPathLocations();
-  CHECK_LE(spaces.size(), boot_class_path_locations.size());
+  const std::vector<std::string>& boot_class_path = runtime->GetBootClassPath();
+  if (boot_class_path.size() != spaces.size()) {
+    *error_msg = StringPrintf("Boot class path has %zu components but there are %zu image spaces.",
+                              boot_class_path.size(),
+                              spaces.size());
+    return false;
+  }
   for (size_t i = 0u, size = spaces.size(); i != size; ++i) {
     // Boot class loader, use a null handle.
     std::vector<std::unique_ptr<const DexFile>> dex_files;
     if (!AddImageSpace(spaces[i],
                        ScopedNullHandle<mirror::ClassLoader>(),
                        /*dex_elements=*/ nullptr,
-                       /*dex_location=*/ boot_class_path_locations[i].c_str(),
+                       /*dex_location=*/ boot_class_path[i].c_str(),
                        /*out*/&dex_files,
                        error_msg)) {
       return false;
@@ -1064,15 +1069,6 @@
   return true;
 }
 
-void ClassLinker::AddExtraBootDexFiles(
-    Thread* self,
-    std::vector<std::unique_ptr<const DexFile>>&& additional_dex_files) {
-  for (std::unique_ptr<const DexFile>& dex_file : additional_dex_files) {
-    AppendToBootClassPath(self, *dex_file);
-    boot_dex_files_.push_back(std::move(dex_file));
-  }
-}
-
 bool ClassLinker::IsBootClassLoader(ScopedObjectAccessAlreadyRunnable& soa,
                                     ObjPtr<mirror::ClassLoader> class_loader) {
   return class_loader == nullptr ||
diff --git a/runtime/class_linker.h b/runtime/class_linker.h
index d0a7c9b..d3eab7c 100644
--- a/runtime/class_linker.h
+++ b/runtime/class_linker.h
@@ -127,12 +127,6 @@
       REQUIRES_SHARED(Locks::mutator_lock_)
       REQUIRES(!Locks::dex_lock_);
 
-  // Add boot class path dex files that were not included in the boot image.
-  // ClassLinker takes ownership of these dex files.
-  void AddExtraBootDexFiles(Thread* self,
-                            std::vector<std::unique_ptr<const DexFile>>&& additional_dex_files)
-      REQUIRES_SHARED(Locks::mutator_lock_);
-
   // Add an image space to the class linker, may fix up classloader fields and dex cache fields.
   // The dex files that were newly opened for the space are placed in the out argument
   // out_dex_files. Returns true if the operation succeeded.
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/dexopt_test.cc b/runtime/dexopt_test.cc
index 7f697d1..b46c933 100644
--- a/runtime/dexopt_test.cc
+++ b/runtime/dexopt_test.cc
@@ -116,19 +116,19 @@
   ASSERT_TRUE(odex_file.get() != nullptr) << error_msg;
   EXPECT_EQ(filter, odex_file->GetCompilerFilter());
 
-  std::string boot_image_checksums = gc::space::ImageSpace::GetBootClassPathChecksums(
-      Runtime::Current()->GetBootClassPath(), image_location, kRuntimeISA, &error_msg);
-  ASSERT_FALSE(boot_image_checksums.empty()) << error_msg;
-
+  std::unique_ptr<ImageHeader> image_header(
+          gc::space::ImageSpace::ReadImageHeader(image_location.c_str(),
+                                                 kRuntimeISA,
+                                                 &error_msg));
+  ASSERT_TRUE(image_header != nullptr) << error_msg;
   const OatHeader& oat_header = odex_file->GetOatHeader();
+  uint32_t boot_image_checksum = image_header->GetImageChecksum();
 
   if (CompilerFilter::DependsOnImageChecksum(filter)) {
-    const char* checksums = oat_header.GetStoreValueByKey(OatHeader::kBootClassPathChecksumsKey);
-    ASSERT_TRUE(checksums != nullptr);
     if (with_alternate_image) {
-      EXPECT_NE(boot_image_checksums, checksums);
+      EXPECT_NE(boot_image_checksum, oat_header.GetBootImageChecksum());
     } else {
-      EXPECT_EQ(boot_image_checksums, checksums);
+      EXPECT_EQ(boot_image_checksum, oat_header.GetBootImageChecksum());
     }
   }
 }
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..6c55450 100644
--- a/runtime/gc/space/image_space.cc
+++ b/runtime/gc/space/image_space.cc
@@ -28,7 +28,6 @@
 
 #include "art_field-inl.h"
 #include "art_method-inl.h"
-#include "base/array_ref.h"
 #include "base/bit_memory_region.h"
 #include "base/callee_save_type.h"
 #include "base/enums.h"
@@ -45,6 +44,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"
@@ -60,7 +60,6 @@
 namespace gc {
 namespace space {
 
-using android::base::StringAppendF;
 using android::base::StringPrintf;
 
 Atomic<uint32_t> ImageSpace::bitmap_index_(0);
@@ -684,30 +683,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 +777,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 +854,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 +878,7 @@
         *image_header,
         file->Fd(),
         logger,
-        thread_pool,
+        thread_pool != nullptr ? thread_pool->get() : nullptr,
         image_reservation,
         error_msg);
     if (!map.IsValid()) {
@@ -995,8 +1015,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();
@@ -1546,10 +1565,8 @@
       *error_msg = StringPrintf("Cannot read header of %s", filename.c_str());
       return false;
     }
-    if (system_hdr.GetComponentCount() == 0u ||
-        system_hdr.GetComponentCount() > boot_class_path_.size()) {
-      *error_msg = StringPrintf("Unexpected component count in %s, received %u, "
-                                    "expected non-zero and <= %zu",
+    if (system_hdr.GetComponentCount() != boot_class_path_.size()) {
+      *error_msg = StringPrintf("Unexpected component count in %s, received %u, expected %zu",
                                 filename.c_str(),
                                 system_hdr.GetComponentCount(),
                                 boot_class_path_.size());
@@ -1566,12 +1583,10 @@
       return false;
     }
 
-    ArrayRef<const std::string> provided_locations(boot_class_path_locations_.data(),
-                                                   system_hdr.GetComponentCount());
     std::vector<std::string> locations =
-        ExpandMultiImageLocations(provided_locations, image_location_);
+        ExpandMultiImageLocations(boot_class_path_locations_, image_location_);
     std::vector<std::string> filenames =
-        ExpandMultiImageLocations(provided_locations, filename);
+        ExpandMultiImageLocations(boot_class_path_locations_, filename);
     DCHECK_EQ(locations.size(), filenames.size());
     std::vector<std::unique_ptr<ImageSpace>> spaces;
     spaces.reserve(locations.size());
@@ -1590,7 +1605,7 @@
     }
     for (size_t i = 0u, size = spaces.size(); i != size; ++i) {
       std::string expected_boot_class_path =
-          (i == 0u) ? android::base::Join(provided_locations, ':') : std::string();
+          (i == 0u) ? android::base::Join(boot_class_path_locations_, ':') : std::string();
       if (!OpenOatFile(spaces[i].get(),
                        boot_class_path_[i],
                        expected_boot_class_path,
@@ -2324,113 +2339,9 @@
   return true;
 }
 
-std::string ImageSpace::GetBootClassPathChecksums(const std::vector<std::string>& boot_class_path,
-                                                  const std::string& image_location,
-                                                  InstructionSet image_isa,
-                                                  /*out*/std::string* error_msg) {
-  std::string system_filename;
-  bool has_system = false;
-  std::string cache_filename;
-  bool has_cache = false;
-  bool dalvik_cache_exists = false;
-  bool is_global_cache = false;
-  if (!FindImageFilename(image_location.c_str(),
-                         image_isa,
-                         &system_filename,
-                         &has_system,
-                         &cache_filename,
-                         &dalvik_cache_exists,
-                         &has_cache,
-                         &is_global_cache)) {
-    *error_msg = StringPrintf("Unable to find image file for %s and %s",
-                              image_location.c_str(),
-                              GetInstructionSetString(image_isa));
-    return std::string();
-  }
-
-  DCHECK(has_system || has_cache);
-  const std::string& filename = has_system ? system_filename : cache_filename;
-  std::unique_ptr<ImageHeader> header = ReadSpecificImageHeader(filename.c_str(), error_msg);
-  if (header == nullptr) {
-    return std::string();
-  }
-  if (header->GetComponentCount() == 0u || header->GetComponentCount() > boot_class_path.size()) {
-    *error_msg = StringPrintf("Unexpected component count in %s, received %u, "
-                                  "expected non-zero and <= %zu",
-                              filename.c_str(),
-                              header->GetComponentCount(),
-                              boot_class_path.size());
-    return std::string();
-  }
-
-  std::string boot_image_checksum =
-      StringPrintf("i;%d/%08x", header->GetComponentCount(), header->GetImageChecksum());
-  ArrayRef<const std::string> boot_class_path_tail =
-      ArrayRef<const std::string>(boot_class_path).SubArray(header->GetComponentCount());
-  for (const std::string& bcp_filename : boot_class_path_tail) {
-    std::vector<std::unique_ptr<const DexFile>> dex_files;
-    const ArtDexFileLoader dex_file_loader;
-    if (!dex_file_loader.Open(bcp_filename.c_str(),
-                              bcp_filename,  // The location does not matter here.
-                              /*verify=*/ false,
-                              /*verify_checksum=*/ false,
-                              error_msg,
-                              &dex_files)) {
-      return std::string();
-    }
-    DCHECK(!dex_files.empty());
-    StringAppendF(&boot_image_checksum, ":d");
-    for (const std::unique_ptr<const DexFile>& dex_file : dex_files) {
-      StringAppendF(&boot_image_checksum, "/%08x", dex_file->GetLocationChecksum());
-    }
-  }
-  return boot_image_checksum;
-}
-
-std::string ImageSpace::GetBootClassPathChecksums(
-    const std::vector<ImageSpace*>& image_spaces,
-    const std::vector<const DexFile*>& boot_class_path) {
-  DCHECK(!image_spaces.empty());
-  const ImageHeader& primary_header = image_spaces.front()->GetImageHeader();
-  uint32_t component_count = primary_header.GetComponentCount();
-  DCHECK_EQ(component_count, image_spaces.size());
-  std::string boot_image_checksum =
-      StringPrintf("i;%d/%08x", component_count, primary_header.GetImageChecksum());
-  size_t pos = 0u;
-  for (const ImageSpace* space : image_spaces) {
-    size_t num_dex_files = space->oat_file_non_owned_->GetOatDexFiles().size();
-    if (kIsDebugBuild) {
-      CHECK_NE(num_dex_files, 0u);
-      CHECK_LE(space->oat_file_non_owned_->GetOatDexFiles().size(), boot_class_path.size() - pos);
-      for (size_t i = 0; i != num_dex_files; ++i) {
-        CHECK_EQ(space->oat_file_non_owned_->GetOatDexFiles()[i]->GetDexFileLocation(),
-                 boot_class_path[pos + i]->GetLocation());
-      }
-    }
-    pos += num_dex_files;
-  }
-  ArrayRef<const DexFile* const> boot_class_path_tail =
-      ArrayRef<const DexFile* const>(boot_class_path).SubArray(pos);
-  DCHECK(boot_class_path_tail.empty() ||
-         !DexFileLoader::IsMultiDexLocation(boot_class_path_tail.front()->GetLocation().c_str()));
-  for (const DexFile* dex_file : boot_class_path_tail) {
-    if (!DexFileLoader::IsMultiDexLocation(dex_file->GetLocation().c_str())) {
-      StringAppendF(&boot_image_checksum, ":d");
-    }
-    StringAppendF(&boot_image_checksum, "/%08x", dex_file->GetLocationChecksum());
-  }
-  return boot_image_checksum;
-}
-
 std::vector<std::string> ImageSpace::ExpandMultiImageLocations(
     const std::vector<std::string>& dex_locations,
     const std::string& image_location) {
-  return ExpandMultiImageLocations(ArrayRef<const std::string>(dex_locations), image_location);
-}
-
-std::vector<std::string> ImageSpace::ExpandMultiImageLocations(
-    ArrayRef<const std::string> dex_locations,
-    const std::string& image_location) {
   DCHECK(!dex_locations.empty());
 
   // Find the path.
diff --git a/runtime/gc/space/image_space.h b/runtime/gc/space/image_space.h
index 14e364a..9049a53 100644
--- a/runtime/gc/space/image_space.h
+++ b/runtime/gc/space/image_space.h
@@ -24,8 +24,6 @@
 
 namespace art {
 
-template <typename T> class ArrayRef;
-class DexFile;
 class OatFile;
 
 namespace gc {
@@ -126,19 +124,6 @@
                                 bool* has_data,
                                 bool *is_global_cache);
 
-  // Returns the checksums for the boot image and extra boot class path dex files,
-  // based on the boot class path, image location and ISA (may differ from the ISA of an
-  // initialized Runtime). The boot image and dex files do not need to be loaded in memory.
-  static std::string GetBootClassPathChecksums(const std::vector<std::string>& boot_class_path,
-                                               const std::string& image_location,
-                                               InstructionSet image_isa,
-                                               /*out*/std::string* error_msg);
-
-  // Returns the checksums for the boot image and extra boot class path dex files,
-  // based on the boot image and boot class path dex files loaded in memory.
-  static std::string GetBootClassPathChecksums(const std::vector<ImageSpace*>& image_spaces,
-                                               const std::vector<const DexFile*>& boot_class_path);
-
   // Expand a single image location to multi-image locations based on the dex locations.
   static std::vector<std::string> ExpandMultiImageLocations(
       const std::vector<std::string>& dex_locations,
@@ -203,11 +188,6 @@
   friend class Space;
 
  private:
-  // Internal overload that takes ArrayRef<> instead of vector<>.
-  static std::vector<std::string> ExpandMultiImageLocations(
-      ArrayRef<const std::string> dex_locations,
-      const std::string& image_location);
-
   class BootImageLoader;
   template <typename ReferenceVisitor>
   class ClassTableVisitor;
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/oat.cc b/runtime/oat.cc
index d7c968f..e931b28 100644
--- a/runtime/oat.cc
+++ b/runtime/oat.cc
@@ -79,7 +79,8 @@
       quick_generic_jni_trampoline_offset_(0),
       quick_imt_conflict_trampoline_offset_(0),
       quick_resolution_trampoline_offset_(0),
-      quick_to_interpreter_bridge_offset_(0) {
+      quick_to_interpreter_bridge_offset_(0),
+      boot_image_checksum_(0) {
   // Don't want asserts in header as they would be checked in each file that includes it. But the
   // fields are private, so we check inside a method.
   static_assert(sizeof(magic_) == sizeof(kOatMagic),
@@ -315,6 +316,16 @@
   quick_to_interpreter_bridge_offset_ = offset;
 }
 
+uint32_t OatHeader::GetBootImageChecksum() const {
+  CHECK(IsValid());
+  return boot_image_checksum_;
+}
+
+void OatHeader::SetBootImageChecksum(uint32_t boot_image_checksum) {
+  CHECK(IsValid());
+  boot_image_checksum_ = boot_image_checksum;
+}
+
 uint32_t OatHeader::GetKeyValueStoreSize() const {
   CHECK(IsValid());
   return key_value_store_size_;
diff --git a/runtime/oat.h b/runtime/oat.h
index ded1489..b09c81e 100644
--- a/runtime/oat.h
+++ b/runtime/oat.h
@@ -31,8 +31,8 @@
 class PACKED(4) OatHeader {
  public:
   static constexpr uint8_t kOatMagic[] = { 'o', 'a', 't', '\n' };
-  // Last oat version changed reason: Partial boot image.
-  static constexpr uint8_t kOatVersion[] = { '1', '6', '6', '\0' };
+  // Last oat version changed reason: Pass boot class path to LoadBootImage.
+  static constexpr uint8_t kOatVersion[] = { '1', '6', '5', '\0' };
 
   static constexpr const char* kDex2OatCmdLineKey = "dex2oat-cmdline";
   static constexpr const char* kDebuggableKey = "debuggable";
@@ -40,7 +40,6 @@
   static constexpr const char* kCompilerFilter = "compiler-filter";
   static constexpr const char* kClassPathKey = "classpath";
   static constexpr const char* kBootClassPathKey = "bootclasspath";
-  static constexpr const char* kBootClassPathChecksumsKey = "bootclasspath-checksums";
   static constexpr const char* kConcurrentCopying = "concurrent-copying";
   static constexpr const char* kCompilationReasonKey = "compilation-reason";
 
@@ -94,6 +93,9 @@
   InstructionSet GetInstructionSet() const;
   uint32_t GetInstructionSetFeaturesBitmap() const;
 
+  uint32_t GetBootImageChecksum() const;
+  void SetBootImageChecksum(uint32_t boot_image_checksum);
+
   uint32_t GetKeyValueStoreSize() const;
   const uint8_t* GetKeyValueStore() const;
   const char* GetStoreValueByKey(const char* key) const;
@@ -135,6 +137,8 @@
   uint32_t quick_resolution_trampoline_offset_;
   uint32_t quick_to_interpreter_bridge_offset_;
 
+  uint32_t boot_image_checksum_;
+
   uint32_t key_value_store_size_;
   uint8_t key_value_store_[0];  // note variable width data at end
 
diff --git a/runtime/oat_file_assistant.cc b/runtime/oat_file_assistant.cc
index 8b81bb9..6f32b98 100644
--- a/runtime/oat_file_assistant.cc
+++ b/runtime/oat_file_assistant.cc
@@ -419,7 +419,7 @@
       // starts up.
       LOG(WARNING) << "Dex location " << dex_location_ << " does not seem to include dex file. "
         << "Allow oat file use. This is potentially dangerous.";
-    } else if (!image_info->ValidateBootClassPathChecksums(file)) {
+    } else if (file.GetOatHeader().GetBootImageChecksum() != image_info->boot_image_checksum) {
       VLOG(oat) << "Oat image checksum does not match image checksum.";
       return kOatBootImageOutOfDate;
     }
@@ -560,13 +560,6 @@
   return required_dex_checksums_found_ ? &cached_required_dex_checksums_ : nullptr;
 }
 
-bool OatFileAssistant::ImageInfo::ValidateBootClassPathChecksums(const OatFile& oat_file) const {
-  const char* oat_boot_class_path_checksums =
-      oat_file.GetOatHeader().GetStoreValueByKey(OatHeader::kBootClassPathChecksumsKey);
-  return oat_boot_class_path_checksums != nullptr &&
-         oat_boot_class_path_checksums == boot_class_path_checksums;
-}
-
 std::unique_ptr<OatFileAssistant::ImageInfo>
 OatFileAssistant::ImageInfo::GetRuntimeImageInfo(InstructionSet isa, std::string* error_msg) {
   CHECK(error_msg != nullptr);
@@ -574,11 +567,14 @@
   Runtime* runtime = Runtime::Current();
   std::unique_ptr<ImageInfo> info(new ImageInfo());
   info->location = runtime->GetImageLocation();
-  info->boot_class_path_checksums = gc::space::ImageSpace::GetBootClassPathChecksums(
-      runtime->GetBootClassPath(), info->location, isa, error_msg);
-  if (info->boot_class_path_checksums.empty()) {
+
+  std::unique_ptr<ImageHeader> image_header(
+      gc::space::ImageSpace::ReadImageHeader(info->location.c_str(), isa, error_msg));
+  if (image_header == nullptr) {
     return nullptr;
   }
+
+  info->boot_image_checksum = image_header->GetImageChecksum();
   return info;
 }
 
diff --git a/runtime/oat_file_assistant.h b/runtime/oat_file_assistant.h
index def55b8..09c9d3b 100644
--- a/runtime/oat_file_assistant.h
+++ b/runtime/oat_file_assistant.h
@@ -246,10 +246,8 @@
 
  private:
   struct ImageInfo {
-    bool ValidateBootClassPathChecksums(const OatFile& oat_file) const;
-
+    uint32_t boot_image_checksum = 0;
     std::string location;
-    std::string boot_class_path_checksums;
 
     static std::unique_ptr<ImageInfo> GetRuntimeImageInfo(InstructionSet isa,
                                                           std::string* error_msg);
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index c5a8a23..a40ffbd 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.
@@ -971,8 +974,8 @@
   VLOG(startup) << "Runtime::StartDaemonThreads exiting";
 }
 
-static size_t OpenDexFiles(ArrayRef<const std::string> dex_filenames,
-                           ArrayRef<const std::string> dex_locations,
+static size_t OpenDexFiles(const std::vector<std::string>& dex_filenames,
+                           const std::vector<std::string>& dex_locations,
                            std::vector<std::unique_ptr<const DexFile>>* dex_files) {
   DCHECK(dex_files != nullptr) << "OpenDexFiles: out-param is nullptr";
   size_t failure_count = 0;
@@ -1429,21 +1432,6 @@
         GetInternTable()->AddImageStringsToTable(image_space, VoidFunctor());
       }
     }
-    if (heap_->GetBootImageSpaces().size() != GetBootClassPath().size()) {
-      // The boot image did not contain all boot class path components. Load the rest.
-      DCHECK_LT(heap_->GetBootImageSpaces().size(), GetBootClassPath().size());
-      size_t start = heap_->GetBootImageSpaces().size();
-      DCHECK_LT(start, GetBootClassPath().size());
-      std::vector<std::unique_ptr<const DexFile>> extra_boot_class_path;
-      if (runtime_options.Exists(Opt::BootClassPathDexList)) {
-        extra_boot_class_path.swap(*runtime_options.GetOrDefault(Opt::BootClassPathDexList));
-      } else {
-        OpenDexFiles(ArrayRef<const std::string>(GetBootClassPath()).SubArray(start),
-                     ArrayRef<const std::string>(GetBootClassPathLocations()).SubArray(start),
-                     &extra_boot_class_path);
-      }
-      class_linker_->AddExtraBootDexFiles(self, std::move(extra_boot_class_path));
-    }
     if (IsJavaDebuggable()) {
       // Now that we have loaded the boot image, deoptimize its methods if we are running
       // debuggable, as the code may have been compiled non-debuggable.
@@ -1454,9 +1442,7 @@
     if (runtime_options.Exists(Opt::BootClassPathDexList)) {
       boot_class_path.swap(*runtime_options.GetOrDefault(Opt::BootClassPathDexList));
     } else {
-      OpenDexFiles(ArrayRef<const std::string>(GetBootClassPath()),
-                   ArrayRef<const std::string>(GetBootClassPathLocations()),
-                   &boot_class_path);
+      OpenDexFiles(GetBootClassPath(), GetBootClassPathLocations(), &boot_class_path);
     }
     if (!class_linker_->InitWithoutImage(std::move(boot_class_path), &error_msg)) {
       LOG(ERROR) << "Could not initialize without image: " << error_msg;
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/etc/run-test-jar b/test/etc/run-test-jar
index 4c31ee5..16106ab 100755
--- a/test/etc/run-test-jar
+++ b/test/etc/run-test-jar
@@ -548,10 +548,7 @@
   exit
 fi
 
-# Note: This must start with the CORE_IMG_JARS in Android.common_path.mk
-# because that's what we use for compiling the core.art image.
-# It may contain additional modules from TEST_CORE_JARS.
-bpath_modules="core-oj core-libart core-simple okhttp bouncycastle conscrypt"
+bpath_modules="core-oj core-libart core-simple conscrypt okhttp bouncycastle"
 if [ "${HOST}" = "y" ]; then
     framework="${ANDROID_HOST_OUT}/framework"
     if [ "${ANDROID_HOST_OUT:0:${#ANDROID_BUILD_TOP}+1}" = "${ANDROID_BUILD_TOP}/" ]; then
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",
diff --git a/tools/bootjars.sh b/tools/bootjars.sh
index 9f22827..ad6ee6b 100755
--- a/tools/bootjars.sh
+++ b/tools/bootjars.sh
@@ -72,10 +72,8 @@
   # FIXME: The soong invocation we're using for getting the variables does not give us anything
   # defined in Android.common_path.mk, otherwise we would just use HOST-/TARGET_TEST_CORE_JARS.
 
-  # Note: This must start with the CORE_IMG_JARS in Android.common_path.mk
-  # because that's what we use for compiling the core.art image.
-  # It may contain additional modules from TEST_CORE_JARS.
-  core_jars_list="core-oj core-libart core-simple"
+  # The core_jars_list must match the TEST_CORE_JARS variable in the Android.common_path.mk .
+  core_jars_list="core-oj core-libart core-simple conscrypt okhttp bouncycastle"
   core_jars_suffix=
   if [[ $mode == target ]]; then
     core_jars_suffix=-testdex
diff --git a/tools/run-jdwp-tests.sh b/tools/run-jdwp-tests.sh
index c85a5ed..f4a2dc1 100755
--- a/tools/run-jdwp-tests.sh
+++ b/tools/run-jdwp-tests.sh
@@ -55,10 +55,9 @@
   done
 }
 
-# Note: This must start with the CORE_IMG_JARS in Android.common_path.mk
+# Note: This must match the TEST_CORE_JARS in Android.common_path.mk
 # because that's what we use for compiling the core.art image.
-# It may contain additional modules from TEST_CORE_JARS.
-BOOT_CLASSPATH_JARS="core-oj core-libart core-simple okhttp bouncycastle conscrypt"
+BOOT_CLASSPATH_JARS="core-oj core-libart core-simple conscrypt okhttp bouncycastle"
 
 vm_args=""
 art="$android_root/bin/art"
diff --git a/tools/run-libcore-tests.sh b/tools/run-libcore-tests.sh
index 63fe81b..63f1fce 100755
--- a/tools/run-libcore-tests.sh
+++ b/tools/run-libcore-tests.sh
@@ -57,10 +57,9 @@
   done
 }
 
-# Note: This must start with the CORE_IMG_JARS in Android.common_path.mk
+# Note: This must match the TEST_CORE_JARS in Android.common_path.mk
 # because that's what we use for compiling the core.art image.
-# It may contain additional modules from TEST_CORE_JARS.
-BOOT_CLASSPATH_JARS="core-oj core-libart core-simple okhttp bouncycastle conscrypt"
+BOOT_CLASSPATH_JARS="core-oj core-libart core-simple conscrypt okhttp bouncycastle"
 
 DEPS="core-tests jsr166-tests mockito-target"