Revert "Generate app image at runtime."

This reverts commit 1ebfebc865ef6661b16e38011ea8fbb6d8608e61.

Reason for revert: b/261576631

Change-Id: I3f2b9c97cab2e4178ec8dc7bf9447d69481b907d
diff --git a/runtime/Android.bp b/runtime/Android.bp
index 166c342..1cba4b5 100644
--- a/runtime/Android.bp
+++ b/runtime/Android.bp
@@ -278,7 +278,6 @@
         "runtime.cc",
         "runtime_callbacks.cc",
         "runtime_common.cc",
-        "runtime_image.cc",
         "runtime_intrinsics.cc",
         "runtime_options.cc",
         "scoped_thread_state_change.cc",
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index ca3d399..dc2ccb4 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -1432,7 +1432,7 @@
   }
 }
 
-bool ClassLinker::IsBootClassLoader(ObjPtr<mirror::Object> class_loader) {
+bool ClassLinker::IsBootClassLoader(ObjPtr<mirror::ClassLoader> class_loader) {
   return class_loader == nullptr ||
          WellKnownClasses::java_lang_BootClassLoader == class_loader->GetClass();
 }
@@ -1999,8 +1999,9 @@
       hs.NewHandle(dex_caches_object->AsObjectArray<mirror::DexCache>()));
   Handle<mirror::ObjectArray<mirror::Class>> class_roots(hs.NewHandle(
       header.GetImageRoot(ImageHeader::kClassRoots)->AsObjectArray<mirror::Class>()));
-  MutableHandle<mirror::Object> special_root(hs.NewHandle(
-      app_image ? header.GetImageRoot(ImageHeader::kSpecialRoots) : nullptr));
+  MutableHandle<mirror::ClassLoader> image_class_loader(hs.NewHandle(
+      app_image ? header.GetImageRoot(ImageHeader::kAppImageClassLoader)->AsClassLoader()
+                : nullptr));
   DCHECK(class_roots != nullptr);
   if (class_roots->GetLength() != static_cast<int32_t>(ClassRoot::kMax)) {
     *error_msg = StringPrintf("Expected %d class roots but got %d",
@@ -2047,30 +2048,9 @@
 
   if (app_image) {
     ScopedAssertNoThreadSuspension sants("Checking app image");
-    if (special_root == nullptr) {
-      *error_msg = "Unexpected null special root in app image";
-      return false;
-    } else if (special_root->IsIntArray()) {
-      size_t count = special_root->AsIntArray()->GetLength();
-      if (oat_file->GetVdexFile()->GetNumberOfDexFiles() != count) {
-        *error_msg = "Cheksums count does not match";
-        return false;
-      }
-      static_assert(sizeof(VdexFile::VdexChecksum) == sizeof(int32_t));
-      const VdexFile::VdexChecksum* art_checksums =
-          reinterpret_cast<VdexFile::VdexChecksum*>(special_root->AsIntArray()->GetData());
-      const VdexFile::VdexChecksum* vdex_checksums =
-          oat_file->GetVdexFile()->GetDexChecksumsArray();
-      if (memcmp(art_checksums, vdex_checksums, sizeof(VdexFile::VdexChecksum) * count) != 0) {
-        *error_msg = "Image and vdex cheksums did not match";
-        return false;
-      }
-    } else if (IsBootClassLoader(special_root.Get())) {
+    if (IsBootClassLoader(image_class_loader.Get())) {
       *error_msg = "Unexpected BootClassLoader in app image";
       return false;
-    } else if (!special_root->IsClassLoader()) {
-      *error_msg = "Unexpected special root in app image";
-      return false;
     }
   }
 
diff --git a/runtime/class_linker.h b/runtime/class_linker.h
index bafbd7b..37e9979 100644
--- a/runtime/class_linker.h
+++ b/runtime/class_linker.h
@@ -723,7 +723,7 @@
       REQUIRES(!Locks::classlinker_classes_lock_)
       REQUIRES_SHARED(Locks::mutator_lock_);
 
-  static bool IsBootClassLoader(ObjPtr<mirror::Object> class_loader)
+  static bool IsBootClassLoader(ObjPtr<mirror::ClassLoader> class_loader)
       REQUIRES_SHARED(Locks::mutator_lock_);
 
   ArtMethod* AddMethodToConflictTable(ObjPtr<mirror::Class> klass,
diff --git a/runtime/gc/accounting/space_bitmap.h b/runtime/gc/accounting/space_bitmap.h
index e318933..c87b31e 100644
--- a/runtime/gc/accounting/space_bitmap.h
+++ b/runtime/gc/accounting/space_bitmap.h
@@ -164,7 +164,7 @@
   void CopyFrom(SpaceBitmap* source_bitmap);
 
   // Starting address of our internal storage.
-  Atomic<uintptr_t>* Begin() const {
+  Atomic<uintptr_t>* Begin() {
     return bitmap_begin_;
   }
 
diff --git a/runtime/gc/space/image_space.cc b/runtime/gc/space/image_space.cc
index 48e5eb6..5667266 100644
--- a/runtime/gc/space/image_space.cc
+++ b/runtime/gc/space/image_space.cc
@@ -521,8 +521,7 @@
       // Check the oat file checksum.
       const uint32_t oat_checksum = oat_file->GetOatHeader().GetChecksum();
       const uint32_t image_oat_checksum = image_header.GetOatChecksum();
-      // Note image_oat_checksum is 0 for images generated by the runtime.
-      if (image_oat_checksum != 0u && oat_checksum != image_oat_checksum) {
+      if (oat_checksum != image_oat_checksum) {
         *error_msg = StringPrintf("Oat checksum 0x%x does not match the image one 0x%x in image %s",
                                   oat_checksum,
                                   image_oat_checksum,
diff --git a/runtime/image.cc b/runtime/image.cc
index 5030b49..b8536db 100644
--- a/runtime/image.cc
+++ b/runtime/image.cc
@@ -67,14 +67,12 @@
     image_roots_(image_roots),
     pointer_size_(pointer_size) {
   CHECK_EQ(image_begin, RoundUp(image_begin, kPageSize));
-  if (oat_checksum != 0u) {
-    CHECK_EQ(oat_file_begin, RoundUp(oat_file_begin, kPageSize));
-    CHECK_EQ(oat_data_begin, RoundUp(oat_data_begin, kPageSize));
-    CHECK_LT(image_roots, oat_file_begin);
-    CHECK_LE(oat_file_begin, oat_data_begin);
-    CHECK_LT(oat_data_begin, oat_data_end);
-    CHECK_LE(oat_data_end, oat_file_end);
-  }
+  CHECK_EQ(oat_file_begin, RoundUp(oat_file_begin, kPageSize));
+  CHECK_EQ(oat_data_begin, RoundUp(oat_data_begin, kPageSize));
+  CHECK_LT(image_roots, oat_file_begin);
+  CHECK_LE(oat_file_begin, oat_data_begin);
+  CHECK_LT(oat_data_begin, oat_data_end);
+  CHECK_LE(oat_data_end, oat_file_end);
   CHECK(ValidPointerSize(pointer_size_)) << pointer_size_;
   memcpy(magic_, kImageMagic, sizeof(kImageMagic));
   memcpy(version_, kImageVersion, sizeof(kImageVersion));
@@ -131,16 +129,14 @@
   if (image_begin_ >= image_begin_ + image_size_) {
     return false;
   }
-  if (oat_checksum_ != 0u) {
-    if (oat_file_begin_ > oat_file_end_) {
-      return false;
-    }
-    if (oat_data_begin_ > oat_data_end_) {
-      return false;
-    }
-    if (oat_file_begin_ >= oat_data_begin_) {
-      return false;
-    }
+  if (oat_file_begin_ > oat_file_end_) {
+    return false;
+  }
+  if (oat_data_begin_ > oat_data_end_) {
+    return false;
+  }
+  if (oat_file_begin_ >= oat_data_begin_) {
+    return false;
   }
   return true;
 }
diff --git a/runtime/image.h b/runtime/image.h
index caf1aa5..bc0c9dd 100644
--- a/runtime/image.h
+++ b/runtime/image.h
@@ -230,8 +230,6 @@
     // Aliases.
     kAppImageClassLoader = kSpecialRoots,   // The class loader used to build the app image.
     kBootImageLiveObjects = kSpecialRoots,  // Array of boot image objects that must be kept live.
-    kAppImageDexChecksums = kSpecialRoots,  // Array of dex checksums for app images generated by
-                                            // the runtime.
   };
 
   enum BootImageLiveObjects {
@@ -504,7 +502,6 @@
   uint32_t blocks_count_ = 0u;
 
   friend class linker::ImageWriter;
-  friend class RuntimeImageHelper;
 };
 
 /*
diff --git a/runtime/oat_file_manager.cc b/runtime/oat_file_manager.cc
index e9c0ddd..c64b9a3 100644
--- a/runtime/oat_file_manager.cc
+++ b/runtime/oat_file_manager.cc
@@ -50,7 +50,6 @@
 #include "oat_file.h"
 #include "oat_file_assistant.h"
 #include "obj_ptr-inl.h"
-#include "runtime_image.h"
 #include "scoped_thread_state_change-inl.h"
 #include "thread-current-inl.h"
 #include "thread_list.h"
@@ -214,6 +213,12 @@
     oat_file_assistant->GetOptimizationStatus(
         &odex_location, &compilation_filter, &compilation_reason, &odex_status);
 
+    Runtime::Current()->GetAppInfo()->RegisterOdexStatus(
+        dex_location,
+        compilation_filter,
+        compilation_reason,
+        odex_status);
+
     ScopedTrace odex_loading(StringPrintf(
         "location=%s status=%s filter=%s reason=%s",
         odex_location.c_str(),
@@ -243,95 +248,74 @@
         << " best_oat_file-location=" << oat_file->GetLocation();
 
     if (oat_file != nullptr) {
-      bool compilation_enabled =
-          CompilerFilter::IsAotCompilationEnabled(oat_file->GetCompilerFilter());
       // Load the dex files from the oat file.
       bool added_image_space = false;
-      if (should_madvise_vdex_and_odex) {
-        VLOG(oat) << "Madvising oat file: " << oat_file->GetLocation();
-        size_t madvise_size_limit = runtime->GetMadviseWillNeedSizeOdex();
-        Runtime::MadviseFileForRange(madvise_size_limit,
-                                     oat_file->Size(),
-                                     oat_file->Begin(),
-                                     oat_file->End(),
-                                     oat_file->GetLocation());
-      }
+      if (oat_file->IsExecutable()) {
+        if (should_madvise_vdex_and_odex) {
+          VLOG(oat) << "Madvising oat file: " << oat_file->GetLocation();
+          size_t madvise_size_limit = runtime->GetMadviseWillNeedSizeOdex();
+          Runtime::MadviseFileForRange(madvise_size_limit,
+                                       oat_file->Size(),
+                                       oat_file->Begin(),
+                                       oat_file->End(),
+                                       oat_file->GetLocation());
+        }
 
-      ScopedTrace app_image_timing("AppImage:Loading");
+        ScopedTrace app_image_timing("AppImage:Loading");
 
-      // We need to throw away the image space if we are debuggable but the oat-file source of the
-      // image is not otherwise we might get classes with inlined methods or other such things.
-      std::unique_ptr<gc::space::ImageSpace> image_space;
-      if (ShouldLoadAppImage(oat_file.get())) {
-        if (oat_file->IsExecutable()) {
-          // App images generated by the compiler can only be used if the oat file
-          // is executable.
+        // We need to throw away the image space if we are debuggable but the oat-file source of the
+        // image is not otherwise we might get classes with inlined methods or other such things.
+        std::unique_ptr<gc::space::ImageSpace> image_space;
+        if (ShouldLoadAppImage(oat_file.get())) {
           image_space = oat_file_assistant->OpenImageSpace(oat_file.get());
         }
-        if (image_space == nullptr && !compilation_enabled) {
-          std::string art_file = RuntimeImage::GetRuntimeImagePath(dex_location);
-          std::string error_msg;
+        if (image_space != nullptr) {
           ScopedObjectAccess soa(self);
-          image_space = gc::space::ImageSpace::CreateFromAppImage(
-              art_file.c_str(), oat_file.get(), &error_msg);
-          if (image_space == nullptr) {
-            VLOG(image) << "Could not load runtime generated app image: " << error_msg;
-          }
-        }
-      }
-      if (image_space != nullptr) {
-        ScopedObjectAccess soa(self);
-        StackHandleScope<1> hs(self);
-        Handle<mirror::ClassLoader> h_loader(
-            hs.NewHandle(soa.Decode<mirror::ClassLoader>(class_loader)));
-        // Can not load app image without class loader.
-        if (h_loader != nullptr) {
-          std::string temp_error_msg;
-          // Add image space has a race condition since other threads could be reading from the
-          // spaces array.
-          {
-            ScopedThreadSuspension sts(self, ThreadState::kSuspended);
-            gc::ScopedGCCriticalSection gcs(self,
-                                            gc::kGcCauseAddRemoveAppImageSpace,
-                                            gc::kCollectorTypeAddRemoveAppImageSpace);
-            ScopedSuspendAll ssa("Add image space");
-            runtime->GetHeap()->AddSpace(image_space.get());
-          }
-          {
-            ScopedTrace image_space_timing("Adding image space");
-            added_image_space = runtime->GetClassLinker()->AddImageSpace(image_space.get(),
-                                                                         h_loader,
-                                                                         /*out*/&dex_files,
-                                                                         /*out*/&temp_error_msg);
-          }
-          if (added_image_space) {
-            // Successfully added image space to heap, release the map so that it does not get
-            // freed.
-            image_space.release();  // NOLINT b/117926937
-
-            // Register for tracking.
-            for (const auto& dex_file : dex_files) {
-              dex::tracking::RegisterDexFile(dex_file.get());
-            }
-
-            if (!compilation_enabled) {
-              // Update the filter we are going to report to 'speed-profile'.
-              // Ideally, we would also update the compiler filter of the odex
-              // file, but at this point it's just too late.
-              compilation_filter = CompilerFilter::NameOfFilter(CompilerFilter::kSpeedProfile);
-            }
-          } else {
-            LOG(INFO) << "Failed to add image file: " << temp_error_msg;
-            dex_files.clear();
+          StackHandleScope<1> hs(self);
+          Handle<mirror::ClassLoader> h_loader(
+              hs.NewHandle(soa.Decode<mirror::ClassLoader>(class_loader)));
+          // Can not load app image without class loader.
+          if (h_loader != nullptr) {
+            std::string temp_error_msg;
+            // Add image space has a race condition since other threads could be reading from the
+            // spaces array.
             {
               ScopedThreadSuspension sts(self, ThreadState::kSuspended);
               gc::ScopedGCCriticalSection gcs(self,
                                               gc::kGcCauseAddRemoveAppImageSpace,
                                               gc::kCollectorTypeAddRemoveAppImageSpace);
-              ScopedSuspendAll ssa("Remove image space");
-              runtime->GetHeap()->RemoveSpace(image_space.get());
+              ScopedSuspendAll ssa("Add image space");
+              runtime->GetHeap()->AddSpace(image_space.get());
             }
-            // Non-fatal, don't update error_msg.
+            {
+              ScopedTrace image_space_timing("Adding image space");
+              added_image_space = runtime->GetClassLinker()->AddImageSpace(image_space.get(),
+                                                                           h_loader,
+                                                                           /*out*/&dex_files,
+                                                                           /*out*/&temp_error_msg);
+            }
+            if (added_image_space) {
+              // Successfully added image space to heap, release the map so that it does not get
+              // freed.
+              image_space.release();  // NOLINT b/117926937
+
+              // Register for tracking.
+              for (const auto& dex_file : dex_files) {
+                dex::tracking::RegisterDexFile(dex_file.get());
+              }
+            } else {
+              LOG(INFO) << "Failed to add image file " << temp_error_msg;
+              dex_files.clear();
+              {
+                ScopedThreadSuspension sts(self, ThreadState::kSuspended);
+                gc::ScopedGCCriticalSection gcs(self,
+                                                gc::kGcCauseAddRemoveAppImageSpace,
+                                                gc::kCollectorTypeAddRemoveAppImageSpace);
+                ScopedSuspendAll ssa("Remove image space");
+                runtime->GetHeap()->RemoveSpace(image_space.get());
+              }
+              // Non-fatal, don't update error_msg.
+            }
           }
         }
       }
@@ -433,12 +417,6 @@
         }
       }
     }
-
-    Runtime::Current()->GetAppInfo()->RegisterOdexStatus(
-        dex_location,
-        compilation_filter,
-        compilation_reason,
-        odex_status);
   }
 
   // If we arrive here with an empty dex files list, it means we fail to load
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index d997256..e99eaec 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -165,7 +165,6 @@
 #include "reflection.h"
 #include "runtime_callbacks.h"
 #include "runtime_common.h"
-#include "runtime_image.h"
 #include "runtime_intrinsics.h"
 #include "runtime_options.h"
 #include "scoped_thread_state_change-inl.h"
@@ -3370,19 +3369,6 @@
   void Run(Thread* self) override {
     VLOG(startup) << "NotifyStartupCompletedTask running";
     Runtime* const runtime = Runtime::Current();
-    {
-      std::string compiler_filter;
-      std::string compilation_reason;
-      runtime->GetAppInfo()->GetPrimaryApkOptimizationStatus(&compiler_filter, &compilation_reason);
-      CompilerFilter::Filter filter;
-      if (CompilerFilter::ParseCompilerFilter(compiler_filter.c_str(), &filter) &&
-          !CompilerFilter::IsAotCompilationEnabled(filter)) {
-        std::string error_msg;
-        if (!RuntimeImage::WriteImageToDisk(&error_msg)) {
-          LOG(DEBUG) << "Could not write temporary image to disk " << error_msg;
-        }
-      }
-    }
     // Fetch the startup linear alloc before the checkpoint to play nice with
     // 1002-notify-startup test which resets the startup state.
     std::unique_ptr<LinearAlloc> startup_linear_alloc(runtime->ReleaseStartupLinearAlloc());
diff --git a/runtime/runtime_image.cc b/runtime/runtime_image.cc
deleted file mode 100644
index f088eb1..0000000
--- a/runtime/runtime_image.cc
+++ /dev/null
@@ -1,564 +0,0 @@
-/*
- * Copyright (C) 2022 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 "runtime_image.h"
-
-#include <lz4.h>
-#include <sstream>
-#include <unistd.h>
-
-#include "android-base/stringprintf.h"
-
-#include "base/bit_utils.h"
-#include "base/file_utils.h"
-#include "base/length_prefixed_array.h"
-#include "base/unix_file/fd_file.h"
-#include "base/utils.h"
-#include "class_loader_utils.h"
-#include "class_root-inl.h"
-#include "gc/space/image_space.h"
-#include "image.h"
-#include "mirror/object-inl.h"
-#include "mirror/object-refvisitor-inl.h"
-#include "mirror/object_array-alloc-inl.h"
-#include "mirror/object_array-inl.h"
-#include "mirror/object_array.h"
-#include "scoped_thread_state_change-inl.h"
-#include "vdex_file.h"
-
-namespace art {
-
-/**
- * Helper class to generate an app image at runtime.
- */
-class RuntimeImageHelper {
- public:
-  explicit RuntimeImageHelper(gc::Heap* heap) :
-    boot_image_begin_(heap->GetBootImagesStartAddress()),
-    boot_image_size_(heap->GetBootImagesSize()),
-    image_begin_(boot_image_begin_ + boot_image_size_),
-    // Note: image relocation considers the image header in the bitmap.
-    object_section_size_(sizeof(ImageHeader)) {}
-
-  bool Generate(std::string* error_msg) {
-    if (!WriteImageRoot(error_msg)) {
-      return false;
-    }
-
-    // Generate the sections information stored in the header.
-    dchecked_vector<ImageSection> sections(ImageHeader::kSectionCount);
-    CreateImageSections(sections);
-
-    // Generate the bitmap section, stored page aligned after the sections data
-    // and of size `object_section_size_` page aligned.
-    size_t sections_end = sections[ImageHeader::kSectionMetadata].End();
-    image_bitmap_ = gc::accounting::ContinuousSpaceBitmap::Create(
-        "image bitmap",
-        reinterpret_cast<uint8_t*>(image_begin_),
-        RoundUp(object_section_size_, kPageSize));
-    for (uint32_t offset : object_offsets_) {
-      DCHECK(IsAligned<kObjectAlignment>(image_begin_ + sizeof(ImageHeader) + offset));
-      image_bitmap_.Set(
-          reinterpret_cast<mirror::Object*>(image_begin_ + sizeof(ImageHeader) + offset));
-    }
-    const size_t bitmap_bytes = image_bitmap_.Size();
-    auto* bitmap_section = &sections[ImageHeader::kSectionImageBitmap];
-    *bitmap_section = ImageSection(RoundUp(sections_end, kPageSize),
-                                   RoundUp(bitmap_bytes, kPageSize));
-
-    // Compute boot image checksum and boot image components, to be stored in
-    // the header.
-    gc::Heap* const heap = Runtime::Current()->GetHeap();
-    uint32_t boot_image_components = 0u;
-    uint32_t boot_image_checksums = 0u;
-    const std::vector<gc::space::ImageSpace*>& image_spaces = heap->GetBootImageSpaces();
-    for (size_t i = 0u, size = image_spaces.size(); i != size; ) {
-      const ImageHeader& header = image_spaces[i]->GetImageHeader();
-      boot_image_components += header.GetComponentCount();
-      boot_image_checksums ^= header.GetImageChecksum();
-      DCHECK_LE(header.GetImageSpaceCount(), size - i);
-      i += header.GetImageSpaceCount();
-    }
-
-    header_ = ImageHeader(
-        /* image_reservation_size= */ RoundUp(sections_end, kPageSize),
-        /* component_count= */ 1,
-        image_begin_,
-        sections_end,
-        sections.data(),
-        /* image_roots= */ image_begin_ + sizeof(ImageHeader),
-        /* oat_checksum= */ 0,
-        /* oat_file_begin= */ 0,
-        /* oat_data_begin= */ 0,
-        /* oat_data_end= */ 0,
-        /* oat_file_end= */ 0,
-        heap->GetBootImagesStartAddress(),
-        heap->GetBootImagesSize(),
-        boot_image_components,
-        boot_image_checksums,
-        static_cast<uint32_t>(kRuntimePointerSize));
-
-    // Data size includes everything except the bitmap.
-    header_.data_size_ = sections_end;
-
-    // Write image methods - needs to happen after creation of the header.
-    WriteImageMethods();
-
-    return true;
-  }
-
-  const std::vector<uint8_t>& GetData() const {
-    return image_data_;
-  }
-
-  const ImageHeader& GetHeader() const {
-    return header_;
-  }
-
-  const gc::accounting::ContinuousSpaceBitmap& GetImageBitmap() const {
-    return image_bitmap_;
-  }
-
-  const std::string& GetDexLocation() const {
-    return dex_location_;
-  }
-
- private:
-  bool IsInBootImage(const void* obj) const {
-    return reinterpret_cast<uintptr_t>(obj) - boot_image_begin_ < boot_image_size_;
-  }
-
-  // Returns a pointer that can be stored in `image_data_`:
-  // - The pointer itself for boot image objects,
-  // - The offset in the image for all other objects.
-  mirror::Object* GetOrComputeImageAddress(ObjPtr<mirror::Object> object)
-      REQUIRES_SHARED(Locks::mutator_lock_) {
-    if (object == nullptr || IsInBootImage(object.Ptr())) {
-      DCHECK(object == nullptr || Runtime::Current()->GetHeap()->ObjectIsInBootImageSpace(object));
-      return object.Ptr();
-    } else if (object->IsClassLoader()) {
-      // DexCache and Class point to class loaders. For runtime-generated app
-      // images, we don't encode the class loader. It will be set when the
-      // runtime is loading the image.
-      return nullptr;
-    } else {
-      uint32_t offset = CopyObject(object);
-      return reinterpret_cast<mirror::Object*>(image_begin_ + sizeof(ImageHeader) + offset);
-    }
-  }
-
-  void CreateImageSections(dchecked_vector<ImageSection>& sections) const {
-    sections[ImageHeader::kSectionObjects] =
-        ImageSection(0u, object_section_size_);
-    sections[ImageHeader::kSectionArtFields] =
-        ImageSection(sections[ImageHeader::kSectionObjects].End(), 0u);
-    sections[ImageHeader::kSectionArtMethods] =
-        ImageSection(sections[ImageHeader::kSectionArtFields].End(), 0u);
-    sections[ImageHeader::kSectionImTables] =
-        ImageSection(sections[ImageHeader::kSectionArtMethods].End(), 0u);
-    sections[ImageHeader::kSectionIMTConflictTables] =
-        ImageSection(sections[ImageHeader::kSectionImTables].End(), 0u);
-    sections[ImageHeader::kSectionRuntimeMethods] =
-        ImageSection(sections[ImageHeader::kSectionIMTConflictTables].End(), 0u);
-
-    // Round up to the alignment the string table expects. See HashSet::WriteToMemory.
-    size_t cur_pos = RoundUp(sections[ImageHeader::kSectionRuntimeMethods].End(), sizeof(uint64_t));
-
-    sections[ImageHeader::kSectionInternedStrings] =
-        ImageSection(cur_pos, 0u);
-
-    // Obtain the new position and round it up to the appropriate alignment.
-    cur_pos = RoundUp(sections[ImageHeader::kSectionInternedStrings].End(), sizeof(uint64_t));
-
-    sections[ImageHeader::kSectionClassTable] =
-        ImageSection(cur_pos, 0u);
-
-    // Round up to the alignment of the offsets we are going to store.
-    cur_pos = RoundUp(sections[ImageHeader::kSectionClassTable].End(), sizeof(uint32_t));
-
-    sections[ImageHeader::kSectionStringReferenceOffsets] =
-        ImageSection(cur_pos, 0u);
-
-    // Round up to the alignment of the offsets we are going to store.
-    cur_pos =
-        RoundUp(sections[ImageHeader::kSectionStringReferenceOffsets].End(), sizeof(uint32_t));
-
-    sections[ImageHeader::kSectionMetadata] =
-        ImageSection(cur_pos, 0u);
-  }
-
-  bool WriteImageRoot(std::string* error_msg) {
-    ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
-    ScopedObjectAccess soa(Thread::Current());
-    VariableSizedHandleScope handles(soa.Self());
-
-    Handle<mirror::Class> object_array_class = handles.NewHandle(
-        GetClassRoot<mirror::ObjectArray<mirror::Object>>(class_linker));
-
-    Handle<mirror::ObjectArray<mirror::Object>> image_roots = handles.NewHandle(
-        mirror::ObjectArray<mirror::Object>::Alloc(
-            soa.Self(), object_array_class.Get(), ImageHeader::kImageRootsMax));
-
-    if (image_roots == nullptr) {
-      DCHECK(soa.Self()->IsExceptionPending());
-      soa.Self()->ClearException();
-      *error_msg = "Out of memory when trying to generate a runtime app image";
-      return false;
-    }
-
-    // Find the dex files that will be used for generating the app image.
-    dchecked_vector<Handle<mirror::DexCache>> dex_caches;
-    FindDexCaches(soa.Self(), dex_caches, handles);
-
-    if (dex_caches.size() == 0) {
-      *error_msg = "Did not find dex caches to generate an app image";
-      return false;
-    }
-    const OatDexFile* oat_dex_file = dex_caches[0]->GetDexFile()->GetOatDexFile();
-    VdexFile* vdex_file = oat_dex_file->GetOatFile()->GetVdexFile();
-    // The first entry in `dex_caches` contains the location of the primary APK.
-    dex_location_ = oat_dex_file->GetDexFileLocation();
-
-    size_t number_of_dex_files = vdex_file->GetNumberOfDexFiles();
-    if (number_of_dex_files != dex_caches.size()) {
-      // This means some dex files haven't been executed. For simplicity, just
-      // register them and recollect dex caches.
-      Handle<mirror::ClassLoader> loader = handles.NewHandle(dex_caches[0]->GetClassLoader());
-      VisitClassLoaderDexFiles(soa.Self(), loader, [&](const art::DexFile* dex_file)
-          REQUIRES_SHARED(Locks::mutator_lock_) {
-        class_linker->RegisterDexFile(*dex_file, dex_caches[0]->GetClassLoader());
-        return true;  // Continue with other dex files.
-      });
-      dex_caches.clear();
-      FindDexCaches(soa.Self(), dex_caches, handles);
-      if (number_of_dex_files != dex_caches.size()) {
-        *error_msg = "Number of dex caches does not match number of dex files in the primary APK";
-        return false;
-      }
-    }
-
-    // Create and populate the checksums aray.
-    Handle<mirror::IntArray> checksums_array = handles.NewHandle(
-        mirror::IntArray::Alloc(soa.Self(), number_of_dex_files));
-
-    if (checksums_array == nullptr) {
-      DCHECK(soa.Self()->IsExceptionPending());
-      soa.Self()->ClearException();
-      *error_msg = "Out of memory when trying to generate a runtime app image";
-      return false;
-    }
-
-    const VdexFile::VdexChecksum* checksums = vdex_file->GetDexChecksumsArray();
-    static_assert(sizeof(VdexFile::VdexChecksum) == sizeof(int32_t));
-    for (uint32_t i = 0; i < number_of_dex_files; ++i) {
-      checksums_array->Set(i, checksums[i]);
-    }
-
-    // Create and populate the dex caches aray.
-    Handle<mirror::ObjectArray<mirror::Object>> dex_cache_array = handles.NewHandle(
-        mirror::ObjectArray<mirror::Object>::Alloc(
-            soa.Self(), object_array_class.Get(), dex_caches.size()));
-
-    if (dex_cache_array == nullptr) {
-      DCHECK(soa.Self()->IsExceptionPending());
-      soa.Self()->ClearException();
-      *error_msg = "Out of memory when trying to generate a runtime app image";
-      return false;
-    }
-
-    for (uint32_t i = 0; i < dex_caches.size(); ++i) {
-      dex_cache_array->Set(i, dex_caches[i].Get());
-    }
-
-    image_roots->Set(ImageHeader::kDexCaches, dex_cache_array.Get());
-    image_roots->Set(ImageHeader::kClassRoots, class_linker->GetClassRoots());
-    image_roots->Set(ImageHeader::kAppImageDexChecksums, checksums_array.Get());
-
-    // Now that we have created all objects needed for the `image_roots`, copy
-    // it into the buffer. Note that this will recursively copy all objects
-    // contained in `image_roots`. That's acceptable as we don't have cycles,
-    // nor a deep graph.
-    ScopedAssertNoThreadSuspension sants("Writing runtime app image");
-    CopyObject(image_roots.Get());
-    return true;
-  }
-
-  class FixupVisitor {
-   public:
-    FixupVisitor(RuntimeImageHelper* image, size_t copy_offset)
-        : image_(image), copy_offset_(copy_offset) {}
-
-    // We do not visit native roots. These are handled with other logic.
-    void VisitRootIfNonNull(mirror::CompressedReference<mirror::Object>* root ATTRIBUTE_UNUSED)
-        const {
-      LOG(FATAL) << "UNREACHABLE";
-    }
-    void VisitRoot(mirror::CompressedReference<mirror::Object>* root ATTRIBUTE_UNUSED) const {
-      LOG(FATAL) << "UNREACHABLE";
-    }
-
-    void operator()(ObjPtr<mirror::Object> obj,
-                    MemberOffset offset,
-                    bool is_static ATTRIBUTE_UNUSED) const
-        REQUIRES_SHARED(Locks::mutator_lock_) {
-      ObjPtr<mirror::Object> ref = obj->GetFieldObject<mirror::Object>(offset);
-      mirror::Object* address = image_->GetOrComputeImageAddress(ref.Ptr());
-      mirror::Object* copy =
-          reinterpret_cast<mirror::Object*>(image_->image_data_.data() + copy_offset_);
-      copy->GetFieldObjectReferenceAddr<kVerifyNone>(offset)->Assign(address);
-    }
-
-    // java.lang.ref.Reference visitor.
-    void operator()(ObjPtr<mirror::Class> klass ATTRIBUTE_UNUSED,
-                    ObjPtr<mirror::Reference> ref) const
-        REQUIRES_SHARED(Locks::mutator_lock_) {
-      operator()(ref, mirror::Reference::ReferentOffset(), /* is_static */ false);
-    }
-
-   private:
-    RuntimeImageHelper* image_;
-    size_t copy_offset_;
-  };
-
-  // Copy `obj` in `image_data_` and relocate references. Returns the offset
-  // within our buffer.
-  uint32_t CopyObject(ObjPtr<mirror::Object> obj) REQUIRES_SHARED(Locks::mutator_lock_) {
-    // Copy the object in `image_data_`.
-    size_t object_size = obj->SizeOf();
-    size_t offset = image_data_.size();
-    DCHECK(IsAligned<kObjectAlignment>(offset));
-    object_offsets_.push_back(offset);
-    image_data_.resize(RoundUp(image_data_.size() + object_size, kObjectAlignment));
-    memcpy(image_data_.data() + offset, obj.Ptr(), object_size);
-    object_section_size_ += RoundUp(object_size, kObjectAlignment);
-
-    // Fixup reference pointers.
-    FixupVisitor visitor(this, offset);
-    obj->VisitReferences</*kVisitNativeRoots=*/ false>(visitor, visitor);
-
-    // For dex caches, clear pointers to data that will be set at runtime.
-    mirror::Object* copy = reinterpret_cast<mirror::Object*>(image_data_.data() + offset);
-    if (obj->IsDexCache()) {
-      reinterpret_cast<mirror::DexCache*>(copy)->ResetNativeArrays();
-      reinterpret_cast<mirror::DexCache*>(copy)->SetDexFile(nullptr);
-    }
-    return offset;
-  }
-
-  class CollectDexCacheVisitor : public DexCacheVisitor {
-   public:
-    explicit CollectDexCacheVisitor(VariableSizedHandleScope& handles) : handles_(handles) {}
-
-    void Visit(ObjPtr<mirror::DexCache> dex_cache)
-        REQUIRES_SHARED(Locks::dex_lock_, Locks::mutator_lock_) override {
-      dex_caches_.push_back(handles_.NewHandle(dex_cache));
-    }
-    const std::vector<Handle<mirror::DexCache>>& GetDexCaches() const {
-      return dex_caches_;
-    }
-   private:
-    VariableSizedHandleScope& handles_;
-    std::vector<Handle<mirror::DexCache>> dex_caches_;
-  };
-
-  // Find dex caches corresponding to the primary APK.
-  void FindDexCaches(Thread* self,
-                     dchecked_vector<Handle<mirror::DexCache>>& dex_caches,
-                     VariableSizedHandleScope& handles)
-      REQUIRES_SHARED(Locks::mutator_lock_) {
-    DCHECK(dex_caches.empty());
-    // Collect all dex caches.
-    ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
-    CollectDexCacheVisitor visitor(handles);
-    {
-      ReaderMutexLock mu(self, *Locks::dex_lock_);
-      class_linker->VisitDexCaches(&visitor);
-    }
-
-    // Find the primary APK.
-    AppInfo* app_info = Runtime::Current()->GetAppInfo();
-    for (Handle<mirror::DexCache> cache : visitor.GetDexCaches()) {
-      if (app_info->GetRegisteredCodeType(cache->GetDexFile()->GetLocation()) ==
-              AppInfo::CodeType::kPrimaryApk) {
-        dex_caches.push_back(handles.NewHandle(cache.Get()));
-        break;
-      }
-    }
-
-    if (dex_caches.empty()) {
-      return;
-    }
-
-    const OatDexFile* oat_dex_file = dex_caches[0]->GetDexFile()->GetOatDexFile();
-    if (oat_dex_file == nullptr) {
-      // We need a .oat file for loading an app image;
-      dex_caches.clear();
-      return;
-    }
-    const OatFile* oat_file = oat_dex_file->GetOatFile();
-    for (Handle<mirror::DexCache> cache : visitor.GetDexCaches()) {
-      if (cache.Get() != dex_caches[0].Get()) {
-        const OatDexFile* other_oat_dex_file = cache->GetDexFile()->GetOatDexFile();
-        if (other_oat_dex_file != nullptr && other_oat_dex_file->GetOatFile() == oat_file) {
-          dex_caches.push_back(handles.NewHandle(cache.Get()));
-        }
-      }
-    }
-  }
-
-  static uint64_t PointerToUint64(void* ptr) {
-    return reinterpret_cast64<uint64_t>(ptr);
-  }
-
-  void WriteImageMethods() {
-    ScopedObjectAccess soa(Thread::Current());
-    // We can just use plain runtime pointers.
-    Runtime* runtime = Runtime::Current();
-    header_.image_methods_[ImageHeader::kResolutionMethod] =
-        PointerToUint64(runtime->GetResolutionMethod());
-    header_.image_methods_[ImageHeader::kImtConflictMethod] =
-        PointerToUint64(runtime->GetImtConflictMethod());
-    header_.image_methods_[ImageHeader::kImtUnimplementedMethod] =
-        PointerToUint64(runtime->GetImtUnimplementedMethod());
-    header_.image_methods_[ImageHeader::kSaveAllCalleeSavesMethod] =
-        PointerToUint64(runtime->GetCalleeSaveMethod(CalleeSaveType::kSaveAllCalleeSaves));
-    header_.image_methods_[ImageHeader::kSaveRefsOnlyMethod] =
-        PointerToUint64(runtime->GetCalleeSaveMethod(CalleeSaveType::kSaveRefsOnly));
-    header_.image_methods_[ImageHeader::kSaveRefsAndArgsMethod] =
-        PointerToUint64(runtime->GetCalleeSaveMethod(CalleeSaveType::kSaveRefsAndArgs));
-    header_.image_methods_[ImageHeader::kSaveEverythingMethod] =
-        PointerToUint64(runtime->GetCalleeSaveMethod(CalleeSaveType::kSaveEverything));
-    header_.image_methods_[ImageHeader::kSaveEverythingMethodForClinit] =
-        PointerToUint64(runtime->GetCalleeSaveMethod(CalleeSaveType::kSaveEverythingForClinit));
-    header_.image_methods_[ImageHeader::kSaveEverythingMethodForSuspendCheck] =
-        PointerToUint64(
-            runtime->GetCalleeSaveMethod(CalleeSaveType::kSaveEverythingForSuspendCheck));
-  }
-
-  // Header for the image, created at the end once we know the size of all
-  // sections.
-  ImageHeader header_;
-
-  // Contents of the image sections.
-  std::vector<uint8_t> image_data_;
-
-  // Bitmap of live objects in `image_data_`. Populated from `object_offsets_`
-  // once we know `object_section_size`.
-  gc::accounting::ContinuousSpaceBitmap image_bitmap_;
-
-  // A list of offsets in `image_data_` where objects begin.
-  std::vector<uint32_t> object_offsets_;
-
-  // Cached values of boot image information.
-  const uint32_t boot_image_begin_;
-  const uint32_t boot_image_size_;
-
-  // Where the image begins: just after the boot image.
-  const uint32_t image_begin_;
-
-  // Size of the `kSectionObjects` section.
-  size_t object_section_size_;
-
-  // The location of the primary APK / dex file.
-  std::string dex_location_;
-};
-
-std::string RuntimeImage::GetRuntimeImagePath(const std::string& dex_location) {
-  const std::string& data_dir = Runtime::Current()->GetProcessDataDirectory();
-
-  std::string new_location = ReplaceFileExtension(
-      dex_location, (kRuntimePointerSize == PointerSize::k32 ? "art32" : "art64"));
-
-  if (data_dir.empty()) {
-    // The data ditectory is empty for tests.
-    return new_location;
-  } else {
-    std::replace(new_location.begin(), new_location.end(), '/', '@');
-    return data_dir + "/" + new_location;
-  }
-}
-
-bool RuntimeImage::WriteImageToDisk(std::string* error_msg) {
-  gc::Heap* heap = Runtime::Current()->GetHeap();
-  if (!heap->HasBootImageSpace()) {
-    *error_msg = "Cannot generate an app image without a boot image";
-    return false;
-  }
-  RuntimeImageHelper image(heap);
-  if (!image.Generate(error_msg)) {
-    return false;
-  }
-
-  const std::string path = GetRuntimeImagePath(image.GetDexLocation());
-  // We first generate the app image in a temporary file, which we will then
-  // move to `path`.
-  const std::string temp_path = path + std::to_string(getpid());
-  std::unique_ptr<File> out(OS::CreateEmptyFileWriteOnly(temp_path.c_str()));
-  if (out == nullptr) {
-    *error_msg = "Could not open " + path + " for writing";
-    return false;
-  }
-
-  // Write section infos. The header is written at the end in case we get killed.
-  if (!out->Write(reinterpret_cast<const char*>(image.GetData().data()),
-                  image.GetData().size(),
-                  sizeof(ImageHeader))) {
-    *error_msg = "Could not write image data to " + path;
-    out->Unlink();
-    return false;
-  }
-
-  // Write bitmap at aligned offset.
-  size_t aligned_offset = RoundUp(sizeof(ImageHeader) + image.GetData().size(), kPageSize);
-  if (!out->Write(reinterpret_cast<const char*>(image.GetImageBitmap().Begin()),
-                  image.GetImageBitmap().Size(),
-                  aligned_offset)) {
-    *error_msg = "Could not write image bitmap " + path;
-    out->Unlink();
-    return false;
-  }
-
-  // Set the file length page aligned.
-  size_t total_size = aligned_offset + RoundUp(image.GetImageBitmap().Size(), kPageSize);
-  if (out->SetLength(total_size) != 0) {
-    *error_msg = "Could not change size of image " + path;
-    out->Unlink();
-    return false;
-  }
-
-  // Now write header.
-  if (!out->Write(reinterpret_cast<const char*>(&image.GetHeader()), sizeof(ImageHeader), 0u)) {
-    *error_msg = "Could not write image header to " + path;
-    out->Unlink();
-    return false;
-  }
-
-  if (out->FlushClose() != 0) {
-    *error_msg = "Could not flush and close " + path;
-    out->Unlink();
-    return false;
-  }
-
-  if (rename(temp_path.c_str(), path.c_str()) != 0) {
-    *error_msg = "Failed to move runtime app image: " + std::string(strerror(errno));
-    out->Unlink();
-    return false;
-  }
-
-  return true;
-}
-
-}  // namespace art
diff --git a/runtime/runtime_image.h b/runtime/runtime_image.h
deleted file mode 100644
index d494e1c..0000000
--- a/runtime/runtime_image.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (C) 2022 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_RUNTIME_RUNTIME_IMAGE_H_
-#define ART_RUNTIME_RUNTIME_IMAGE_H_
-
-#include <string>
-
-namespace art {
-
-class RuntimeImage {
- public:
-    // Writes an app image for the currently running process.
-  static bool WriteImageToDisk(std::string* error_msg);
-
-  // Gets the path where a runtime-generated app image is stored.
-  static std::string GetRuntimeImagePath(const std::string& dex_location);
-};
-
-}  // namespace art
-
-#endif  // ART_RUNTIME_RUNTIME_IMAGE_H_
diff --git a/test/845-data-image/expected-stderr.txt b/test/845-data-image/expected-stderr.txt
deleted file mode 100644
index e69de29..0000000
--- a/test/845-data-image/expected-stderr.txt
+++ /dev/null
diff --git a/test/845-data-image/expected-stdout.txt b/test/845-data-image/expected-stdout.txt
deleted file mode 100644
index 8db7853..0000000
--- a/test/845-data-image/expected-stdout.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-JNI_OnLoad called
-JNI_OnLoad called
diff --git a/test/845-data-image/info.txt b/test/845-data-image/info.txt
deleted file mode 100644
index dfcd0dd..0000000
--- a/test/845-data-image/info.txt
+++ /dev/null
@@ -1 +0,0 @@
-Test the generation of app image at runtime.
diff --git a/test/845-data-image/run.py b/test/845-data-image/run.py
deleted file mode 100644
index 37c990f..0000000
--- a/test/845-data-image/run.py
+++ /dev/null
@@ -1,24 +0,0 @@
-# Copyright (C) 2022 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.
-
-import sys
-
-# We run the tests by disabling compilation with app image and forcing
-# relocation for better testing.
-# Run the test twice: one run for generating the image, a second run for using
-# the image.
-def run(ctx, args):
-  ctx.default_run(args, app_image=False, relocate=True)
-  # Pass another argument to let the test know it should now expect an image.
-  ctx.default_run(args, app_image=False, relocate=True, test_args=["--second-run"])
diff --git a/test/845-data-image/src-art/Main.java b/test/845-data-image/src-art/Main.java
deleted file mode 100644
index d9da5d4..0000000
--- a/test/845-data-image/src-art/Main.java
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Copyright (C) 2022 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.
- */
-
-import dalvik.system.DexFile;
-import dalvik.system.VMRuntime;
-import java.io.File;
-import java.io.IOException;
-
-public class Main {
-  public static void main(String[] args) throws Exception {
-    System.loadLibrary(args[0]);
-
-    // Register the dex file so that the runtime can pick up which
-    // dex file to compile for the image.
-    File file = null;
-    try {
-      file = createTempFile();
-      String codePath = DEX_LOCATION + "/845-data-image.jar";
-      VMRuntime.registerAppInfo(
-          "test.app",
-          file.getPath(),
-          file.getPath(),
-          new String[] {codePath},
-          VMRuntime.CODE_PATH_TYPE_PRIMARY_APK);
-    } finally {
-      if (file != null) {
-        file.delete();
-      }
-    }
-
-    if (!hasOatFile() || !hasImage()) {
-      // We only generate an app image if there is at least a vdex file and a boot image.
-      return;
-    }
-
-    if (args.length == 2 && "--second-run".equals(args[1])) {
-      DexFile.OptimizationInfo info = VMRuntime.getBaseApkOptimizationInfo();
-      if (!info.isOptimized()) {
-        throw new Error("Expected image to be loaded");
-      }
-    }
-
-    VMRuntime runtime = VMRuntime.getRuntime();
-    runtime.notifyStartupCompleted();
-
-    String filter = getCompilerFilter(Main.class);
-    if ("speed-profile".equals(filter) || "speed".equals(filter)) {
-      // We only generate an app image for filters that don't compile.
-      return;
-    }
-
-    // Wait for the file to be generated.
-    File image = new File(
-        DEX_LOCATION + "/845-data-image.art" + (runtime.is64Bit() ? "64" : "32"));
-    while (!image.exists()) {
-      Thread.yield();
-    }
-  }
-
-  private static native boolean hasOatFile();
-  private static native boolean hasImage();
-  private static native String getCompilerFilter(Class<?> cls);
-
-  private static final String TEMP_FILE_NAME_PREFIX = "temp";
-  private static final String TEMP_FILE_NAME_SUFFIX = "-file";
-  private static final String DEX_LOCATION = System.getenv("DEX_LOCATION");
-
-  private static File createTempFile() throws Exception {
-    try {
-      return File.createTempFile(TEMP_FILE_NAME_PREFIX, TEMP_FILE_NAME_SUFFIX);
-    } catch (IOException e) {
-      System.setProperty("java.io.tmpdir", "/data/local/tmp");
-      try {
-        return File.createTempFile(TEMP_FILE_NAME_PREFIX, TEMP_FILE_NAME_SUFFIX);
-      } catch (IOException e2) {
-        System.setProperty("java.io.tmpdir", "/sdcard");
-        return File.createTempFile(TEMP_FILE_NAME_PREFIX, TEMP_FILE_NAME_SUFFIX);
-      }
-    }
-  }
-}
diff --git a/test/846-multidex-data-image/expected-stderr.txt b/test/846-multidex-data-image/expected-stderr.txt
deleted file mode 100644
index e69de29..0000000
--- a/test/846-multidex-data-image/expected-stderr.txt
+++ /dev/null
diff --git a/test/846-multidex-data-image/expected-stdout.txt b/test/846-multidex-data-image/expected-stdout.txt
deleted file mode 100644
index 8db7853..0000000
--- a/test/846-multidex-data-image/expected-stdout.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-JNI_OnLoad called
-JNI_OnLoad called
diff --git a/test/846-multidex-data-image/info.txt b/test/846-multidex-data-image/info.txt
deleted file mode 100644
index 3b83d2c..0000000
--- a/test/846-multidex-data-image/info.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-Test the generation of app image at runtime, when the primary APK contains
-multiple dex files.
diff --git a/test/846-multidex-data-image/run.py b/test/846-multidex-data-image/run.py
deleted file mode 100644
index 3976af2..0000000
--- a/test/846-multidex-data-image/run.py
+++ /dev/null
@@ -1,23 +0,0 @@
-# Copyright (C) 2022 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.
-
-import sys
-
-# We run the tests by disabling compilation with app image.
-# Run the test twice: one run for generating the image, a second run for using
-# the image.
-def run(ctx, args):
-  ctx.default_run(args, app_image=False)
-  # Pass another argument to let the test know it should now expect an image.
-  ctx.default_run(args, app_image=False, test_args=["--second-run"])
diff --git a/test/846-multidex-data-image/src-art/Main.java b/test/846-multidex-data-image/src-art/Main.java
deleted file mode 100644
index 1169c53..0000000
--- a/test/846-multidex-data-image/src-art/Main.java
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * Copyright (C) 2022 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.
- */
-
-import dalvik.system.DexFile;
-import dalvik.system.VMRuntime;
-import java.io.File;
-import java.io.IOException;
-
-public class Main {
-  public static void main(String[] args) throws Exception {
-    System.loadLibrary(args[0]);
-
-    // Register the dex file so that the runtime can pick up which
-    // dex file to compile for the image.
-    File file = null;
-    try {
-      file = createTempFile();
-      String codePath = DEX_LOCATION + "/846-multidex-data-image.jar";
-      VMRuntime.registerAppInfo(
-          "test.app",
-          file.getPath(),
-          file.getPath(),
-          new String[] {codePath},
-          VMRuntime.CODE_PATH_TYPE_PRIMARY_APK);
-    } finally {
-      if (file != null) {
-        file.delete();
-      }
-    }
-
-    if (!hasOatFile() || !hasImage()) {
-      // We only generate an app image if there is at least a vdex file and a boot image.
-      return;
-    }
-
-    if (args.length == 2 && "--second-run".equals(args[1])) {
-      DexFile.OptimizationInfo info = VMRuntime.getBaseApkOptimizationInfo();
-      if (!info.isOptimized()) {
-        throw new Error("Expected image to be loaded");
-      }
-    }
-
-    VMRuntime runtime = VMRuntime.getRuntime();
-    runtime.notifyStartupCompleted();
-
-    String filter = getCompilerFilter(Main.class);
-    if ("speed-profile".equals(filter) || "speed".equals(filter)) {
-      // We only generate an app image for filters that don't compile.
-      return;
-    }
-
-    // Wait for the file to be generated.
-    File image = new File(
-        DEX_LOCATION + "/846-multidex-data-image.art" + (runtime.is64Bit() ? "64" : "32"));
-    while (!image.exists()) {
-      Thread.yield();
-    }
-
-    // Test that we can load a class from the other dex file. We do this after creating the image to
-    // check that the runtime can deal with a missing dex cache.
-    Class.forName("Foo");
-  }
-
-  private static native boolean hasOatFile();
-  private static native boolean hasImage();
-  private static native String getCompilerFilter(Class<?> cls);
-
-  private static final String TEMP_FILE_NAME_PREFIX = "temp";
-  private static final String TEMP_FILE_NAME_SUFFIX = "-file";
-  private static final String DEX_LOCATION = System.getenv("DEX_LOCATION");
-
-  private static File createTempFile() throws Exception {
-    try {
-      return File.createTempFile(TEMP_FILE_NAME_PREFIX, TEMP_FILE_NAME_SUFFIX);
-    } catch (IOException e) {
-      System.setProperty("java.io.tmpdir", "/data/local/tmp");
-      try {
-        return File.createTempFile(TEMP_FILE_NAME_PREFIX, TEMP_FILE_NAME_SUFFIX);
-      } catch (IOException e2) {
-        System.setProperty("java.io.tmpdir", "/sdcard");
-        return File.createTempFile(TEMP_FILE_NAME_PREFIX, TEMP_FILE_NAME_SUFFIX);
-      }
-    }
-  }
-}
diff --git a/test/846-multidex-data-image/src-multidex/Foo.java b/test/846-multidex-data-image/src-multidex/Foo.java
deleted file mode 100644
index 4e36e88..0000000
--- a/test/846-multidex-data-image/src-multidex/Foo.java
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
- * Copyright (C) 2022 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.
- */
-
-public class Foo {
-}
diff --git a/test/knownfailures.json b/test/knownfailures.json
index f335dd5..b980eac 100644
--- a/test/knownfailures.json
+++ b/test/knownfailures.json
@@ -1162,8 +1162,6 @@
                   "844-exception",
                   "844-exception2",
                   "845-fast-verify",
-                  "845-data-image",
-                  "846-multidex-data-image",
                   "999-redefine-hiddenapi",
                   "1000-non-moving-space-stress",
                   "1001-app-image-regions",