Clean up some image tests.

Make ImageSpaceLoadingTest<false,.,.> use a custom image
location based on ScratchFile to avoid accidentally finding
a pre-compiled boot image in default location.

Add -Xnoimage-dex2oat to Dex2oatImageTest to avoid useless
dex2oat invocations that just slow down the test. Suppress
error messages from image loading that is supposed to fail.
Compile only 3 dex files in TestModesAndFilters to make the
test faster (29s->20s on host).

Test: m test-art-host-gtest
Change-Id: Ia92e85f056027003d2fb50aa871c9fae7a5fdc01
diff --git a/dex2oat/dex2oat_image_test.cc b/dex2oat/dex2oat_image_test.cc
index 9b96494..f03f02c 100644
--- a/dex2oat/dex2oat_image_test.cc
+++ b/dex2oat/dex2oat_image_test.cc
@@ -68,6 +68,11 @@
   void TearDown() override {}
 
  protected:
+  void SetUpRuntimeOptions(RuntimeOptions* options) override {
+    // Disable implicit dex2oat invocations when loading image spaces.
+    options->emplace_back("-Xnoimage-dex2oat", nullptr);
+  }
+
   // Visitors take method and type references
   template <typename MethodVisitor, typename ClassVisitor>
   void VisitLibcoreDexes(const MethodVisitor& method_visitor,
@@ -156,7 +161,8 @@
     args.push_back(arg);
   }
 
-  ImageSizes CompileImageAndGetSizes(const std::vector<std::string>& extra_args) {
+  ImageSizes CompileImageAndGetSizes(ArrayRef<const std::string> dex_files,
+                                     const std::vector<std::string>& extra_args) {
     ImageSizes ret;
     ScratchFile scratch;
     std::string scratch_dir = scratch.GetFilename();
@@ -164,8 +170,6 @@
       scratch_dir.pop_back();
     }
     CHECK(!scratch_dir.empty()) << "No directory " << scratch.GetFilename();
-    std::vector<std::string> libcore_dex_files = GetLibCoreDexFileNames();
-    ArrayRef<const std::string> dex_files(libcore_dex_files);
     std::vector<std::string> local_extra_args = extra_args;
     local_extra_args.push_back(android::base::StringPrintf("--base=0x%08x", kBaseAddress));
     std::string error_msg;
@@ -241,6 +245,38 @@
     }
     return res.StandardSuccess();
   }
+
+  MemMap ReserveCoreImageAddressSpace(/*out*/std::string* error_msg) {
+    constexpr size_t kReservationSize = 256 * MB;  // This should be enough for the compiled images.
+    // Extend to both directions for maximum relocation difference.
+    static_assert(ART_BASE_ADDRESS_MIN_DELTA < 0);
+    static_assert(ART_BASE_ADDRESS_MAX_DELTA > 0);
+    static_assert(IsAligned<kPageSize>(ART_BASE_ADDRESS_MIN_DELTA));
+    static_assert(IsAligned<kPageSize>(ART_BASE_ADDRESS_MAX_DELTA));
+    constexpr size_t kExtra = ART_BASE_ADDRESS_MAX_DELTA - ART_BASE_ADDRESS_MIN_DELTA;
+    uint32_t min_relocated_address = kBaseAddress + ART_BASE_ADDRESS_MIN_DELTA;
+    return MemMap::MapAnonymous("Reservation",
+                                reinterpret_cast<uint8_t*>(min_relocated_address),
+                                kReservationSize + kExtra,
+                                PROT_NONE,
+                                /*low_4gb=*/ true,
+                                /*reuse=*/ false,
+                                /*reservation=*/ nullptr,
+                                error_msg);
+  }
+
+  void CopyDexFiles(const std::string& dir, /*inout*/std::vector<std::string>* dex_files) {
+    CHECK(EndsWith(dir, "/"));
+    for (std::string& dex_file : *dex_files) {
+      size_t slash_pos = dex_file.rfind('/');
+      CHECK_NE(std::string::npos, slash_pos);
+      std::string new_location = dir + dex_file.substr(slash_pos + 1u);
+      std::ifstream src_stream(dex_file, std::ios::binary);
+      std::ofstream dst_stream(new_location, std::ios::binary);
+      dst_stream << src_stream.rdbuf();
+      dex_file = new_location;
+    }
+  }
 };
 
 TEST_F(Dex2oatImageTest, TestModesAndFilters) {
@@ -253,7 +289,17 @@
     // This test is too slow for target builds.
     return;
   }
-  ImageSizes base_sizes = CompileImageAndGetSizes({});
+  // Compile only a subset of the libcore dex files to make this test shorter.
+  std::vector<std::string> libcore_dex_files = GetLibCoreDexFileNames();
+  // The primary image must contain at least core-oj and core-libart to initialize the runtime
+  // and we also need the core-icu4j if we want to compile these with full profile.
+  ASSERT_NE(std::string::npos, libcore_dex_files[0].find("core-oj"));
+  ASSERT_NE(std::string::npos, libcore_dex_files[1].find("core-libart"));
+  ASSERT_NE(std::string::npos, libcore_dex_files[2].find("core-icu4j"));
+  ArrayRef<const std::string> dex_files =
+      ArrayRef<const std::string>(libcore_dex_files).SubArray(/*pos=*/ 0u, /*length=*/ 3u);
+
+  ImageSizes base_sizes = CompileImageAndGetSizes(dex_files, {});
   ImageSizes everything_sizes;
   ImageSizes filter_sizes;
   std::cout << "Base compile sizes " << base_sizes << std::endl;
@@ -265,6 +311,7 @@
                     /*method_frequency=*/ 1u,
                     /*type_frequency=*/ 1u);
     everything_sizes = CompileImageAndGetSizes(
+        dex_files,
         {"--profile-file=" + profile_file.GetFilename(),
          "--compiler-filter=speed-profile"});
     profile_file.Close();
@@ -284,6 +331,7 @@
                     kMethodFrequency,
                     kTypeFrequency);
     filter_sizes = CompileImageAndGetSizes(
+        dex_files,
         {"--profile-file=" + profile_file.GetFilename(),
          "--compiler-filter=speed-profile"});
     profile_file.Close();
@@ -300,6 +348,7 @@
       WriteLine(classes.GetFile(), ref.dex_file->PrettyType(ref.TypeIndex()));
     }, /*method_frequency=*/ 1u, /*class_frequency=*/ 1u);
     ImageSizes image_classes_sizes = CompileImageAndGetSizes(
+        dex_files,
         {"--dirty-image-objects=" + classes.GetFilename()});
     classes.Close();
     std::cout << "Dirty image object sizes " << image_classes_sizes << std::endl;
@@ -307,24 +356,9 @@
 }
 
 TEST_F(Dex2oatImageTest, TestExtension) {
-  constexpr size_t kReservationSize = 256 * MB;  // This should be enough for the compiled images.
-  // Extend to both directions for maximum relocation difference.
-  static_assert(ART_BASE_ADDRESS_MIN_DELTA < 0);
-  static_assert(ART_BASE_ADDRESS_MAX_DELTA > 0);
-  static_assert(IsAligned<kPageSize>(ART_BASE_ADDRESS_MIN_DELTA));
-  static_assert(IsAligned<kPageSize>(ART_BASE_ADDRESS_MAX_DELTA));
-  constexpr size_t kExtra = ART_BASE_ADDRESS_MAX_DELTA - ART_BASE_ADDRESS_MIN_DELTA;
-  uint32_t min_relocated_address = kBaseAddress + ART_BASE_ADDRESS_MIN_DELTA;
   std::string error_msg;
-  MemMap reservation = MemMap::MapAnonymous("Reservation",
-                                            reinterpret_cast<uint8_t*>(min_relocated_address),
-                                            kReservationSize + kExtra,
-                                            PROT_NONE,
-                                            /*low_4gb=*/ true,
-                                            /*reuse=*/ false,
-                                            /*reservation=*/ nullptr,
-                                            &error_msg);
-  ASSERT_TRUE(reservation.IsValid());
+  MemMap reservation = ReserveCoreImageAddressSpace(&error_msg);
+  ASSERT_TRUE(reservation.IsValid()) << error_msg;
 
   ScratchFile scratch;
   std::string scratch_dir = scratch.GetFilename() + "-d";
@@ -343,15 +377,7 @@
   ASSERT_EQ(0, mkdir_result);
   jar_dir += '/';
   std::vector<std::string> libcore_dex_files = GetLibCoreDexFileNames();
-  for (std::string& dex_file : libcore_dex_files) {
-    size_t slash_pos = dex_file.rfind('/');
-    ASSERT_NE(std::string::npos, slash_pos);
-    std::string new_location = jar_dir + dex_file.substr(slash_pos + 1u);
-    std::ifstream src_stream(dex_file, std::ios::binary);
-    std::ofstream dst_stream(new_location, std::ios::binary);
-    dst_stream << src_stream.rdbuf();
-    dex_file = new_location;
-  }
+  CopyDexFiles(jar_dir, &libcore_dex_files);
 
   // Create a profile.
   ScratchFile profile_file;
@@ -415,10 +441,10 @@
   extra_args.push_back("--boot-image=" + base_location);
   bool mid_ok = CompileBootImage(extra_args, filename_prefix, mid_dex_files, &error_msg);
   ASSERT_TRUE(mid_ok) << error_msg;
+  extra_args.resize(extra_args.size() - 3u);
 
   // Try to compile the "tail" without specifying the "mid" extension. This shall fail.
   std::string full_bcp_string = android::base::Join(full_bcp, ':');
-  extra_args.clear();
   AddRuntimeArg(extra_args, "-Xbootclasspath:" + full_bcp_string);
   AddRuntimeArg(extra_args, "-Xbootclasspath-locations:" + full_bcp_string);
   extra_args.push_back("--boot-image=" + base_location);
@@ -454,8 +480,12 @@
                                                 &boot_image_spaces,
                                                 &extra_reservation);
   };
+  auto silent_load = [&](const std::string& image_location) {
+    ScopedLogSeverity quiet(LogSeverity::FATAL);
+    return load(image_location);
+  };
 
-  for (bool r : { false, true}) {
+  for (bool r : { false, true }) {
     relocate = r;
 
     // Load primary image with full path.
@@ -465,13 +495,13 @@
     ASSERT_EQ(head_dex_files.size(), boot_image_spaces.size());
 
     // Fail to load primary image with just the name.
-    load_ok = load(base_name);
+    load_ok = silent_load(base_name);
     ASSERT_FALSE(load_ok);
 
     // Fail to load primary image with a search path.
-    load_ok = load("*");
+    load_ok = silent_load("*");
     ASSERT_FALSE(load_ok);
-    load_ok = load(scratch_dir + "*");
+    load_ok = silent_load(scratch_dir + "*");
     ASSERT_FALSE(load_ok);
 
     // Load the primary and first extension with full path.
@@ -513,17 +543,9 @@
 
   // Now copy the libcore dex files to the `scratch_dir` and retry loading the boot image
   // with BCP in the scratch_dir so that the images can be found based on BCP paths.
-  for (std::string& bcp_component : boot_class_path) {
-    size_t slash_pos = bcp_component.rfind('/');
-    ASSERT_NE(std::string::npos, slash_pos);
-    std::string new_location = scratch_dir + bcp_component.substr(slash_pos + 1u);
-    std::ifstream src_stream(bcp_component, std::ios::binary);
-    std::ofstream dst_stream(new_location, std::ios::binary);
-    dst_stream << src_stream.rdbuf();
-    bcp_component = new_location;
-  }
+  CopyDexFiles(scratch_dir, &boot_class_path);
 
-  for (bool r : { false, true}) {
+  for (bool r : { false, true }) {
     relocate = r;
 
     // Loading the primary image with just the name now succeeds.
@@ -531,9 +553,9 @@
     ASSERT_TRUE(load_ok) << error_msg;
 
     // Loading the primary image with a search path still fails.
-    load_ok = load("*");
+    load_ok = silent_load("*");
     ASSERT_FALSE(load_ok);
-    load_ok = load(scratch_dir + "*");
+    load_ok = silent_load(scratch_dir + "*");
     ASSERT_FALSE(load_ok);
 
     // Load the primary and first extension without paths.
@@ -568,9 +590,9 @@
     ASSERT_EQ(full_bcp.size(), boot_image_spaces.size());
 
     // Fail to load any images with invalid image locations (named component after search paths).
-    load_ok = load(base_location + ":*:" + tail_location);
+    load_ok = silent_load(base_location + ":*:" + tail_location);
     ASSERT_FALSE(load_ok);
-    load_ok = load(base_location + ':' + scratch_dir + "*:" + tail_location);
+    load_ok = silent_load(base_location + ':' + scratch_dir + "*:" + tail_location);
     ASSERT_FALSE(load_ok);
   }
 
diff --git a/runtime/gc/space/image_space_test.cc b/runtime/gc/space/image_space_test.cc
index f3398e9..008793b 100644
--- a/runtime/gc/space/image_space_test.cc
+++ b/runtime/gc/space/image_space_test.cc
@@ -166,10 +166,13 @@
 class ImageSpaceLoadingTest : public CommonRuntimeTest {
  protected:
   void SetUpRuntimeOptions(RuntimeOptions* options) override {
-    if (kImage) {
-      options->emplace_back(android::base::StringPrintf("-Ximage:%s", GetCoreArtLocation().c_str()),
-                            nullptr);
+    std::string image_location = GetCoreArtLocation();
+    if (!kImage) {
+      missing_image_base_ = std::make_unique<ScratchFile>();
+      image_location = missing_image_base_->GetFilename() + ".art";
     }
+    options->emplace_back(android::base::StringPrintf("-Ximage:%s", image_location.c_str()),
+                          nullptr);
     options->emplace_back(kRelocate ? "-Xrelocate" : "-Xnorelocate", nullptr);
     options->emplace_back(kImageDex2oat ? "-Ximage-dex2oat" : "-Xnoimage-dex2oat", nullptr);
 
@@ -194,9 +197,11 @@
       CHECK_EQ(result, 0);
       old_dex2oat_bcp_.reset();
     }
+    missing_image_base_.reset();
   }
 
  private:
+  std::unique_ptr<ScratchFile> missing_image_base_;
   UniqueCPtr<const char[]> old_dex2oat_bcp_;
 };
 
@@ -238,13 +243,13 @@
   }
 
   void TearDown() override {
+    ImageSpaceLoadingTest<false, true, true>::TearDown();
     int result = unlink(bad_dalvik_cache_.c_str());
     CHECK_EQ(result, 0) << strerror(errno);
     result = rmdir(bad_android_data_.c_str());
     CHECK_EQ(result, 0) << strerror(errno);
     result = setenv("ANDROID_DATA", old_android_data_.c_str(), /* replace */ 1);
     CHECK_EQ(result, 0) << strerror(errno);
-    ImageSpaceLoadingTest<false, true, true>::TearDown();
   }
 
  private: