Revert "Do not load app image for class collisions"

This reverts commit d8860b42e47d48fcc47db9d0daf5a1b9432180a1.

Bug: 77342775
Bug: 79200502
Bug: 79575750

Reason for revert: Some regressions in boot time.
Test: test-art-host

Change-Id: Id5e5844b5156d048a54011708378c7cdb0650f68
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index 6b65aca..63518be 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -1257,10 +1257,10 @@
         if (stored_class_loader_context_ == nullptr) {
           Usage("Option --stored-class-loader-context has an incorrect format: %s",
                 stored_context_arg.c_str());
-        } else if (class_loader_context_->VerifyClassLoaderContextMatch(
+        } else if (!class_loader_context_->VerifyClassLoaderContextMatch(
             stored_context_arg,
             /*verify_names*/ false,
-            /*verify_checksums*/ false) != ClassLoaderContext::VerificationResult::kVerifies) {
+            /*verify_checksums*/ false)) {
           Usage(
               "Option --stored-class-loader-context '%s' mismatches --class-loader-context '%s'",
               stored_context_arg.c_str(),
diff --git a/runtime/Android.bp b/runtime/Android.bp
index 64e6796..116453b 100644
--- a/runtime/Android.bp
+++ b/runtime/Android.bp
@@ -422,7 +422,6 @@
     srcs: [
         "arch/instruction_set.h",
         "base/mutex.h",
-        "class_loader_context.h",
         "class_status.h",
         "debugger.h",
         "gc_root.h",
diff --git a/runtime/class_loader_context.cc b/runtime/class_loader_context.cc
index 2bd5411..9817414 100644
--- a/runtime/class_loader_context.cc
+++ b/runtime/class_loader_context.cc
@@ -672,10 +672,9 @@
   return !location.empty() && location[0] == '/';
 }
 
-ClassLoaderContext::VerificationResult ClassLoaderContext::VerifyClassLoaderContextMatch(
-    const std::string& context_spec,
-    bool verify_names,
-    bool verify_checksums) const {
+bool ClassLoaderContext::VerifyClassLoaderContextMatch(const std::string& context_spec,
+                                                       bool verify_names,
+                                                       bool verify_checksums) const {
   if (verify_names || verify_checksums) {
     DCHECK(dex_files_open_attempted_);
     DCHECK(dex_files_open_result_);
@@ -684,21 +683,15 @@
   ClassLoaderContext expected_context;
   if (!expected_context.Parse(context_spec, verify_checksums)) {
     LOG(WARNING) << "Invalid class loader context: " << context_spec;
-    return VerificationResult::kMismatch;
+    return false;
   }
 
   // Special shared library contexts always match. They essentially instruct the runtime
   // to ignore the class path check because the oat file is known to be loaded in different
   // contexts. OatFileManager will further verify if the oat file can be loaded based on the
   // collision check.
-  if (expected_context.special_shared_library_) {
-    // Special case where we are the only entry in the class path.
-    if (class_loader_chain_.size() == 1 && class_loader_chain_[0].classpath.size() == 0) {
-      return VerificationResult::kVerifies;
-    }
-    return VerificationResult::kForcedToSkipChecks;
-  } else if (special_shared_library_) {
-    return VerificationResult::kForcedToSkipChecks;
+  if (special_shared_library_ || expected_context.special_shared_library_) {
+    return true;
   }
 
   if (expected_context.class_loader_chain_.size() != class_loader_chain_.size()) {
@@ -706,7 +699,7 @@
         << expected_context.class_loader_chain_.size()
         << ", actual=" << class_loader_chain_.size()
         << " (" << context_spec << " | " << EncodeContextForOatFile("") << ")";
-    return VerificationResult::kMismatch;
+    return false;
   }
 
   for (size_t i = 0; i < class_loader_chain_.size(); i++) {
@@ -717,14 +710,14 @@
           << ". expected=" << GetClassLoaderTypeName(expected_info.type)
           << ", found=" << GetClassLoaderTypeName(info.type)
           << " (" << context_spec << " | " << EncodeContextForOatFile("") << ")";
-      return VerificationResult::kMismatch;
+      return false;
     }
     if (info.classpath.size() != expected_info.classpath.size()) {
       LOG(WARNING) << "ClassLoaderContext classpath size mismatch for position " << i
             << ". expected=" << expected_info.classpath.size()
             << ", found=" << info.classpath.size()
             << " (" << context_spec << " | " << EncodeContextForOatFile("") << ")";
-      return VerificationResult::kMismatch;
+      return false;
     }
 
     if (verify_checksums) {
@@ -779,7 +772,7 @@
             << ". expected=" << expected_info.classpath[k]
             << ", found=" << info.classpath[k]
             << " (" << context_spec << " | " << EncodeContextForOatFile("") << ")";
-        return VerificationResult::kMismatch;
+        return false;
       }
 
       // Compare the checksums.
@@ -788,11 +781,11 @@
                      << ". expected=" << expected_info.checksums[k]
                      << ", found=" << info.checksums[k]
                      << " (" << context_spec << " | " << EncodeContextForOatFile("") << ")";
-        return VerificationResult::kMismatch;
+        return false;
       }
     }
   }
-  return VerificationResult::kVerifies;
+  return true;
 }
 
 jclass ClassLoaderContext::GetClassLoaderClass(ClassLoaderType type) {
diff --git a/runtime/class_loader_context.h b/runtime/class_loader_context.h
index a4268aa..1c83007 100644
--- a/runtime/class_loader_context.h
+++ b/runtime/class_loader_context.h
@@ -22,10 +22,8 @@
 
 #include "arch/instruction_set.h"
 #include "base/dchecked_vector.h"
-#include "dex/dex_file.h"
 #include "handle_scope.h"
 #include "mirror/class_loader.h"
-#include "oat_file.h"
 #include "scoped_thread_state_change.h"
 
 namespace art {
@@ -36,18 +34,6 @@
 // Utility class which holds the class loader context used during compilation/verification.
 class ClassLoaderContext {
  public:
-  enum class VerificationResult {
-    kVerifies,
-    kForcedToSkipChecks,
-    kMismatch,
-  };
-
-  enum ClassLoaderType {
-    kInvalidClassLoader = 0,
-    kPathClassLoader = 1,
-    kDelegateLastClassLoader = 2
-  };
-
   ~ClassLoaderContext();
 
   // Opens requested class path files and appends them to ClassLoaderInfo::opened_dex_files.
@@ -123,7 +109,7 @@
   // This should be called after OpenDexFiles().
   // Names are only verified if verify_names is true.
   // Checksums are only verified if verify_checksums is true.
-  VerificationResult VerifyClassLoaderContextMatch(const std::string& context_spec,
+  bool VerifyClassLoaderContextMatch(const std::string& context_spec,
                                      bool verify_names = true,
                                      bool verify_checksums = true) const;
 
@@ -155,6 +141,12 @@
   static std::unique_ptr<ClassLoaderContext> Default();
 
  private:
+  enum ClassLoaderType {
+    kInvalidClassLoader = 0,
+    kPathClassLoader = 1,
+    kDelegateLastClassLoader = 2
+  };
+
   struct ClassLoaderInfo {
     // The type of this class loader.
     ClassLoaderType type;
diff --git a/runtime/class_loader_context_test.cc b/runtime/class_loader_context_test.cc
index 5e3f48c..4689ae4 100644
--- a/runtime/class_loader_context_test.cc
+++ b/runtime/class_loader_context_test.cc
@@ -608,17 +608,6 @@
   VerifyClassLoaderPCLFromTestDex(context.get(), 3, "ForClassLoaderA");
 }
 
-
-TEST_F(ClassLoaderContextTest, VerifyClassLoaderContextFirstElement) {
-  std::string context_spec = "PCL[]";
-  std::unique_ptr<ClassLoaderContext> context = ParseContextWithChecksums(context_spec);
-  ASSERT_TRUE(context != nullptr);
-  PretendContextOpenedDexFiles(context.get());
-  // Ensure that the special shared library marks as verified for the first thing in the class path.
-  ASSERT_EQ(context->VerifyClassLoaderContextMatch(OatFile::kSpecialSharedLibrary),
-            ClassLoaderContext::VerificationResult::kVerifies);
-}
-
 TEST_F(ClassLoaderContextTest, VerifyClassLoaderContextMatch) {
   std::string context_spec = "PCL[a.dex*123:b.dex*456];DLC[c.dex*890]";
   std::unique_ptr<ClassLoaderContext> context = ParseContextWithChecksums(context_spec);
@@ -630,36 +619,28 @@
   VerifyClassLoaderPCL(context.get(), 0, "a.dex:b.dex");
   VerifyClassLoaderDLC(context.get(), 1, "c.dex");
 
-  ASSERT_EQ(context->VerifyClassLoaderContextMatch(context_spec),
-            ClassLoaderContext::VerificationResult::kVerifies);
+  ASSERT_TRUE(context->VerifyClassLoaderContextMatch(context_spec));
 
   std::string wrong_class_loader_type = "PCL[a.dex*123:b.dex*456];PCL[c.dex*890]";
-  ASSERT_EQ(context->VerifyClassLoaderContextMatch(wrong_class_loader_type),
-            ClassLoaderContext::VerificationResult::kMismatch);
+  ASSERT_FALSE(context->VerifyClassLoaderContextMatch(wrong_class_loader_type));
 
   std::string wrong_class_loader_order = "DLC[c.dex*890];PCL[a.dex*123:b.dex*456]";
-  ASSERT_EQ(context->VerifyClassLoaderContextMatch(wrong_class_loader_order),
-            ClassLoaderContext::VerificationResult::kMismatch);
+  ASSERT_FALSE(context->VerifyClassLoaderContextMatch(wrong_class_loader_order));
 
   std::string wrong_classpath_order = "PCL[b.dex*456:a.dex*123];DLC[c.dex*890]";
-  ASSERT_EQ(context->VerifyClassLoaderContextMatch(wrong_classpath_order),
-            ClassLoaderContext::VerificationResult::kMismatch);
+  ASSERT_FALSE(context->VerifyClassLoaderContextMatch(wrong_classpath_order));
 
   std::string wrong_checksum = "PCL[a.dex*999:b.dex*456];DLC[c.dex*890]";
-  ASSERT_EQ(context->VerifyClassLoaderContextMatch(wrong_checksum),
-            ClassLoaderContext::VerificationResult::kMismatch);
+  ASSERT_FALSE(context->VerifyClassLoaderContextMatch(wrong_checksum));
 
   std::string wrong_extra_class_loader = "PCL[a.dex*123:b.dex*456];DLC[c.dex*890];PCL[d.dex*321]";
-  ASSERT_EQ(context->VerifyClassLoaderContextMatch(wrong_extra_class_loader),
-            ClassLoaderContext::VerificationResult::kMismatch);
+  ASSERT_FALSE(context->VerifyClassLoaderContextMatch(wrong_extra_class_loader));
 
   std::string wrong_extra_classpath = "PCL[a.dex*123:b.dex*456];DLC[c.dex*890:d.dex*321]";
-  ASSERT_EQ(context->VerifyClassLoaderContextMatch(wrong_extra_classpath),
-            ClassLoaderContext::VerificationResult::kMismatch);
+  ASSERT_FALSE(context->VerifyClassLoaderContextMatch(wrong_extra_classpath));
 
   std::string wrong_spec = "PCL[a.dex*999:b.dex*456];DLC[";
-  ASSERT_EQ(context->VerifyClassLoaderContextMatch(wrong_spec),
-            ClassLoaderContext::VerificationResult::kMismatch);
+  ASSERT_FALSE(context->VerifyClassLoaderContextMatch(wrong_spec));
 }
 
 TEST_F(ClassLoaderContextTest, VerifyClassLoaderContextMatchAfterEncoding) {
@@ -671,8 +652,7 @@
   std::unique_ptr<ClassLoaderContext> context = CreateContextForClassLoader(class_loader_d);
 
   std::string context_with_no_base_dir = context->EncodeContextForOatFile("");
-  ASSERT_EQ(context->VerifyClassLoaderContextMatch(context_with_no_base_dir),
-            ClassLoaderContext::VerificationResult::kVerifies);
+  ASSERT_TRUE(context->VerifyClassLoaderContextMatch(context_with_no_base_dir));
 
   std::string dex_location = GetTestDexFileName("ForClassLoaderA");
   size_t pos = dex_location.rfind('/');
@@ -681,8 +661,7 @@
 
   std::string context_with_base_dir = context->EncodeContextForOatFile(parent);
   ASSERT_NE(context_with_base_dir, context_with_no_base_dir);
-  ASSERT_EQ(context->VerifyClassLoaderContextMatch(context_with_base_dir),
-            ClassLoaderContext::VerificationResult::kVerifies);
+  ASSERT_TRUE(context->VerifyClassLoaderContextMatch(context_with_base_dir));
 }
 
 TEST_F(ClassLoaderContextTest, VerifyClassLoaderContextMatchAfterEncodingMultidex) {
@@ -690,8 +669,7 @@
 
   std::unique_ptr<ClassLoaderContext> context = CreateContextForClassLoader(class_loader);
 
-  ASSERT_EQ(context->VerifyClassLoaderContextMatch(context->EncodeContextForOatFile("")),
-            ClassLoaderContext::VerificationResult::kVerifies);
+  ASSERT_TRUE(context->VerifyClassLoaderContextMatch(context->EncodeContextForOatFile("")));
 }
 
 }  // namespace art
diff --git a/runtime/oat_file_assistant.cc b/runtime/oat_file_assistant.cc
index 241102e..9c8b651 100644
--- a/runtime/oat_file_assistant.cc
+++ b/runtime/oat_file_assistant.cc
@@ -1217,9 +1217,7 @@
     return false;
   }
 
-
-  bool result = context->VerifyClassLoaderContextMatch(file->GetClassLoaderContext()) ==
-      ClassLoaderContext::VerificationResult::kVerifies;
+  bool result = context->VerifyClassLoaderContextMatch(file->GetClassLoaderContext());
   if (!result) {
     VLOG(oat) << "ClassLoaderContext check failed. Context was "
               << file->GetClassLoaderContext()
diff --git a/runtime/oat_file_manager.cc b/runtime/oat_file_manager.cc
index 59a1045..16e6cf3 100644
--- a/runtime/oat_file_manager.cc
+++ b/runtime/oat_file_manager.cc
@@ -276,19 +276,9 @@
   }
 }
 
-static bool CheckClassCollision(const OatFile* oat_file,
-    const ClassLoaderContext* context,
-    std::string* error_msg /*out*/) {
-  std::vector<const DexFile*> dex_files_loaded = context->FlattenOpenedDexFiles();
-
-  // Vector that holds the newly opened dex files live, this is done to prevent leaks.
-  std::vector<std::unique_ptr<const DexFile>> opened_dex_files;
-
-  ScopedTrace st("Collision check");
-  // Add dex files from the oat file to check.
-  std::vector<const DexFile*> dex_files_unloaded;
-  AddDexFilesFromOat(oat_file, &dex_files_unloaded, &opened_dex_files);
-
+static bool CollisionCheck(std::vector<const DexFile*>& dex_files_loaded,
+                           std::vector<const DexFile*>& dex_files_unloaded,
+                           std::string* error_msg /*out*/) {
   // Generate type index information for each dex file.
   std::vector<TypeIndexInfo> loaded_types;
   for (const DexFile* dex_file : dex_files_loaded) {
@@ -365,10 +355,9 @@
 // against the following top element. If the descriptor is the same, it is now checked whether
 // the two elements agree on whether their dex file was from an already-loaded oat-file or the
 // new oat file. Any disagreement indicates a collision.
-OatFileManager::CheckCollisionResult OatFileManager::CheckCollision(
-    const OatFile* oat_file,
-    const ClassLoaderContext* context,
-    /*out*/ std::string* error_msg) const {
+bool OatFileManager::HasCollisions(const OatFile* oat_file,
+                                   const ClassLoaderContext* context,
+                                   std::string* error_msg /*out*/) const {
   DCHECK(oat_file != nullptr);
   DCHECK(error_msg != nullptr);
 
@@ -378,59 +367,28 @@
   // Note that this has correctness implications as we cannot guarantee that the class resolution
   // used during compilation is OK (b/37777332).
   if (context == nullptr) {
-    LOG(WARNING) << "Skipping duplicate class check due to unsupported classloader";
-    return CheckCollisionResult::kSkippedUnsupportedClassLoader;
+      LOG(WARNING) << "Skipping duplicate class check due to unsupported classloader";
+      return false;
   }
 
-  // If the oat file loading context matches the context used during compilation then we accept
+  // If the pat file loading context matches the context used during compilation then we accept
   // the oat file without addition checks
-  ClassLoaderContext::VerificationResult result = context->VerifyClassLoaderContextMatch(
-      oat_file->GetClassLoaderContext(),
-      /*verify_names*/ true,
-      /*verify_checksums*/ true);
-  switch (result) {
-    case ClassLoaderContext::VerificationResult::kForcedToSkipChecks:
-      return CheckCollisionResult::kSkippedClassLoaderContextSharedLibrary;
-    case ClassLoaderContext::VerificationResult::kMismatch:
-      // Mismatched context, do the actual collision check.
-      break;
-    case ClassLoaderContext::VerificationResult::kVerifies:
-      return CheckCollisionResult::kNoCollisions;
+  if (context->VerifyClassLoaderContextMatch(oat_file->GetClassLoaderContext())) {
+    return false;
   }
 
   // The class loader context does not match. Perform a full duplicate classes check.
-  return CheckClassCollision(oat_file, context, error_msg)
-      ? CheckCollisionResult::kPerformedHasCollisions : CheckCollisionResult::kNoCollisions;
-}
 
-bool OatFileManager::AcceptOatFile(CheckCollisionResult result) const {
-  // Take the file only if it has no collisions, or we must take it because of preopting.
-  // Also accept oat files for shared libraries and unsupported class loaders.
-  return result != CheckCollisionResult::kPerformedHasCollisions;
-}
+  std::vector<const DexFile*> dex_files_loaded = context->FlattenOpenedDexFiles();
 
-bool OatFileManager::ShouldLoadAppImage(CheckCollisionResult check_collision_result,
-                                        const OatFile* source_oat_file,
-                                        ClassLoaderContext* context,
-                                        std::string* error_msg) {
-  Runtime* const runtime = Runtime::Current();
-  if (kEnableAppImage && (!runtime->IsJavaDebuggable() || source_oat_file->IsDebuggable())) {
-    // If we verified the class loader context (skipping due to the special marker doesn't
-    // count), then also avoid the collision check.
-    bool load_image = check_collision_result == CheckCollisionResult::kNoCollisions;
-    // If we skipped the collision check, we need to reverify to be sure its OK to load the
-    // image.
-    if (!load_image &&
-        check_collision_result ==
-            CheckCollisionResult::kSkippedClassLoaderContextSharedLibrary) {
-      // We can load the app image only if there are no collisions. If we know the
-      // class loader but didn't do the full collision check in HasCollisions(),
-      // do it now. b/77342775
-      load_image = !CheckClassCollision(source_oat_file, context, error_msg);
-    }
-    return load_image;
-  }
-  return false;
+  // Vector that holds the newly opened dex files live, this is done to prevent leaks.
+  std::vector<std::unique_ptr<const DexFile>> opened_dex_files;
+
+  ScopedTrace st("Collision check");
+  // Add dex files from the oat file to check.
+  std::vector<const DexFile*> dex_files_unloaded;
+  AddDexFilesFromOat(oat_file, &dex_files_unloaded, &opened_dex_files);
+  return CollisionCheck(dex_files_loaded, dex_files_unloaded, error_msg);
 }
 
 std::vector<std::unique_ptr<const DexFile>> OatFileManager::OpenDexFilesFromOat(
@@ -515,17 +473,16 @@
             << reinterpret_cast<uintptr_t>(oat_file.get())
             << " (executable=" << (oat_file != nullptr ? oat_file->IsExecutable() : false) << ")";
 
-  CheckCollisionResult check_collision_result = CheckCollisionResult::kPerformedHasCollisions;
   if ((class_loader != nullptr || dex_elements != nullptr) && oat_file != nullptr) {
     // Prevent oat files from being loaded if no class_loader or dex_elements are provided.
     // This can happen when the deprecated DexFile.<init>(String) is called directly, and it
     // could load oat files without checking the classpath, which would be incorrect.
     // Take the file only if it has no collisions, or we must take it because of preopting.
-    check_collision_result = CheckCollision(oat_file.get(), context.get(), /*out*/ &error_msg);
-    bool accept_oat_file = AcceptOatFile(check_collision_result);
+    bool accept_oat_file =
+        !HasCollisions(oat_file.get(), context.get(), /*out*/ &error_msg);
     if (!accept_oat_file) {
       // Failed the collision check. Print warning.
-      if (runtime->IsDexFileFallbackEnabled()) {
+      if (Runtime::Current()->IsDexFileFallbackEnabled()) {
         if (!oat_file_assistant.HasOriginalDexFiles()) {
           // We need to fallback but don't have original dex files. We have to
           // fallback to opening the existing oat file. This is potentially
@@ -572,11 +529,10 @@
       // 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(check_collision_result,
-                             source_oat_file,
-                             context.get(),
-                             &error_msg)) {
+      if (kEnableAppImage && (!runtime->IsJavaDebuggable() || source_oat_file->IsDebuggable())) {
         image_space = oat_file_assistant.OpenImageSpace(source_oat_file);
+      } else {
+        image_space = nullptr;
       }
       if (image_space != nullptr) {
         ScopedObjectAccess soa(self);
diff --git a/runtime/oat_file_manager.h b/runtime/oat_file_manager.h
index 80456e9..038474e 100644
--- a/runtime/oat_file_manager.h
+++ b/runtime/oat_file_manager.h
@@ -108,39 +108,23 @@
   void SetOnlyUseSystemOatFiles();
 
  private:
-  enum class CheckCollisionResult {
-    kSkippedUnsupportedClassLoader,
-    kSkippedClassLoaderContextSharedLibrary,
-    kNoCollisions,
-    kPerformedHasCollisions,
-  };
-
   // Check that the class loader context of the given oat file matches the given context.
   // This will perform a check that all class loaders in the chain have the same type and
   // classpath.
   // If the context is null (which means the initial class loader was null or unsupported)
-  // this returns kSkippedUnsupportedClassLoader.
+  // this returns false.
   // If the context does not validate the method will check for duplicate class definitions of
   // the given oat file against the oat files (either from the class loaders if possible or all
   // non-boot oat files otherwise).
-  // Return kPerformedHasCollisions if there are any class definition collisions in the oat_file.
-  CheckCollisionResult CheckCollision(const OatFile* oat_file,
-                                      const ClassLoaderContext* context,
-                                      /*out*/ std::string* error_msg) const
+  // Return true if there are any class definition collisions in the oat_file.
+  bool HasCollisions(const OatFile* oat_file,
+                     const ClassLoaderContext* context,
+                     /*out*/ std::string* error_msg) const
       REQUIRES(!Locks::oat_file_manager_lock_);
 
   const OatFile* FindOpenedOatFileFromOatLocationLocked(const std::string& oat_location) const
       REQUIRES(Locks::oat_file_manager_lock_);
 
-  // Return true if we should accept the oat file.
-  bool AcceptOatFile(CheckCollisionResult result) const;
-
-  // Return true if we should attempt to load the app image.
-  bool ShouldLoadAppImage(CheckCollisionResult check_collision_result,
-                          const OatFile* source_oat_file,
-                          ClassLoaderContext* context,
-                          std::string* error_msg);
-
   std::set<std::unique_ptr<const OatFile>> oat_files_ GUARDED_BY(Locks::oat_file_manager_lock_);
   bool have_non_pic_oat_file_;
 
diff --git a/test/172-app-image-twice/check b/test/172-app-image-twice/check
deleted file mode 100755
index 26a97a4..0000000
--- a/test/172-app-image-twice/check
+++ /dev/null
@@ -1,18 +0,0 @@
-#!/bin/bash
-#
-# Copyright (C) 2018 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-# Remove all lines not containing "passed".
-grep "^passed" "$2" | diff --strip-trailing-cr -q "$1" - >/dev/null
diff --git a/test/172-app-image-twice/debug_print_class.cc b/test/172-app-image-twice/debug_print_class.cc
deleted file mode 100644
index 6c3de20..0000000
--- a/test/172-app-image-twice/debug_print_class.cc
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "debug_print.h"
-#include "dex/dex_file.h"
-#include "mirror/class-inl.h"
-#include "scoped_thread_state_change-inl.h"
-#include "thread-current-inl.h"
-
-namespace art {
-
-extern "C" JNIEXPORT void JNICALL Java_Main_debugPrintClass(JNIEnv*, jclass, jclass cls) {
-  ScopedObjectAccess soa(Thread::Current());
-  ObjPtr<mirror::Class> klass = soa.Decode<mirror::Class>(cls);
-  LOG(ERROR) << "klass: " << klass.Ptr() << " dex_file: " << klass->GetDexFile().GetLocation()
-      << "/" << static_cast<const void*>(&klass->GetDexFile())
-      << " " << DescribeSpace(klass);
-}
-
-}  // namespace art
diff --git a/test/172-app-image-twice/expected.txt b/test/172-app-image-twice/expected.txt
deleted file mode 100644
index b0aad4d..0000000
--- a/test/172-app-image-twice/expected.txt
+++ /dev/null
@@ -1 +0,0 @@
-passed
diff --git a/test/172-app-image-twice/info.txt b/test/172-app-image-twice/info.txt
deleted file mode 100644
index 028046e..0000000
--- a/test/172-app-image-twice/info.txt
+++ /dev/null
@@ -1 +0,0 @@
-Regression test for loading the same app image twice.
diff --git a/test/172-app-image-twice/profile b/test/172-app-image-twice/profile
deleted file mode 100644
index 70cb2ef..0000000
--- a/test/172-app-image-twice/profile
+++ /dev/null
@@ -1 +0,0 @@
-LTestClass;
diff --git a/test/172-app-image-twice/run b/test/172-app-image-twice/run
deleted file mode 100644
index aa28190..0000000
--- a/test/172-app-image-twice/run
+++ /dev/null
@@ -1,28 +0,0 @@
-#!/bin/bash
-#
-# Copyright (C) 2018 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-# Build an app image with TestClass (specified by profile) and class loader
-# context that skips the duplicate class checks.
-
-# Target and host use a different shell, and we need to special case the
-# passing of the class loader context marker.
-if [[ "$@" = *" --host "* ]]; then
-  ${RUN} $@ --profile -Xcompiler-option --compiler-filter=speed-profile \
-      -Xcompiler-option --class-loader-context=\&
-else
-  ${RUN} $@ --profile -Xcompiler-option --compiler-filter=speed-profile \
-      -Xcompiler-option '--class-loader-context=\&'
-fi
diff --git a/test/172-app-image-twice/src/Main.java b/test/172-app-image-twice/src/Main.java
deleted file mode 100644
index a1c151a..0000000
--- a/test/172-app-image-twice/src/Main.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-import java.lang.reflect.Method;
-
-public class Main {
-    private static String TEST_NAME = "172-app-image-twice";
-
-    public static void main(String args[]) throws Exception {
-        System.loadLibrary(args[0]);
-
-        Class<?> tc1 = Class.forName("TestClass");
-
-        String dexPath = System.getenv("DEX_LOCATION") + "/" + TEST_NAME + ".jar";
-        Class<?> bdcl = Class.forName("dalvik.system.BaseDexClassLoader");
-        Method addDexPathMethod = bdcl.getDeclaredMethod("addDexPath", String.class);
-        addDexPathMethod.invoke(Main.class.getClassLoader(), dexPath);
-
-        Class<?> tc2 = Class.forName("TestClass");
-
-        // Add extra logging to simulate libcore logging, this logging should not be compared
-        // against.
-        System.out.println("Extra logging");
-
-        if (tc1 != tc2) {
-            System.out.println("Class mismatch!");
-            debugPrintClass(tc1);
-            debugPrintClass(tc2);
-        } else {
-            System.out.println("passed");
-        }
-    }
-
-    public static native void debugPrintClass(Class<?> cls);
-}
diff --git a/test/172-app-image-twice/src/TestClass.java b/test/172-app-image-twice/src/TestClass.java
deleted file mode 100644
index 5381718..0000000
--- a/test/172-app-image-twice/src/TestClass.java
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-public class TestClass {
-}
diff --git a/test/Android.bp b/test/Android.bp
index 76189f6..0c6b449 100644
--- a/test/Android.bp
+++ b/test/Android.bp
@@ -423,7 +423,6 @@
         "154-gc-loop/heap_interface.cc",
         "167-visit-locks/visit_locks.cc",
         "169-threadgroup-jni/jni_daemon_thread.cc",
-        "172-app-image-twice/debug_print_class.cc",
         "1945-proxy-method-arguments/get_args.cc",
         "203-multi-checkpoint/multi_checkpoint.cc",
         "305-other-fault-handler/fault_handler.cc",
diff --git a/test/knownfailures.json b/test/knownfailures.json
index f473a99..f313758 100644
--- a/test/knownfailures.json
+++ b/test/knownfailures.json
@@ -734,7 +734,6 @@
           "164-resolution-trampoline-dex-cache",
           "167-visit-locks",
           "168-vmstack-annotated",
-          "172-app-image-twice",
           "201-built-in-except-detail-messages",
           "203-multi-checkpoint",
           "304-method-tracing",