Device gtests: Use boot.art instead of core.art.

They are essentially the same. We can use boot.art to run gtests
since it is already part of the apex, including the jar files.

This will make it easier to run the tests in atest, since we
will not have to worry about copying core.art to the device.

The long-term goal is to avoid generating core.art altogether.

Couple of tests also require "alternate" image which has no
compiled code. The tests now generate it on-demand in code.

The host gtests still use core.art for now (as there is no
boot.art on host). The plan is to add it in future CLs.

Test: m test-art-host-gtest
Test: ./art/tools/run-gtests.sh
Bug: 147817606
Change-Id: I3a750bb8e60eea0b4a7df1491285feffd5a0161c
diff --git a/dex2oat/dex2oat_image_test.cc b/dex2oat/dex2oat_image_test.cc
index 9f0ea33..9fd632f 100644
--- a/dex2oat/dex2oat_image_test.cc
+++ b/dex2oat/dex2oat_image_test.cc
@@ -164,21 +164,17 @@
   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();
-    while (!scratch_dir.empty() && scratch_dir.back() != '/') {
-      scratch_dir.pop_back();
-    }
-    CHECK(!scratch_dir.empty()) << "No directory " << scratch.GetFilename();
+    ScratchDir scratch;
+    std::string filename_prefix = scratch.GetPath() + "boot";
     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;
-    if (!CompileBootImage(local_extra_args, scratch.GetFilename(), dex_files, &error_msg)) {
-      LOG(ERROR) << "Failed to compile image " << scratch.GetFilename() << error_msg;
+    if (!CompileBootImage(local_extra_args, filename_prefix, dex_files, &error_msg)) {
+      LOG(ERROR) << "Failed to compile image " << filename_prefix << error_msg;
     }
-    std::string art_file = scratch.GetFilename() + ".art";
-    std::string oat_file = scratch.GetFilename() + ".oat";
-    std::string vdex_file = scratch.GetFilename() + ".vdex";
+    std::string art_file = filename_prefix + ".art";
+    std::string oat_file = filename_prefix + ".oat";
+    std::string vdex_file = filename_prefix + ".vdex";
     int64_t art_size = OS::GetFileSizeBytes(art_file.c_str());
     int64_t oat_size = OS::GetFileSizeBytes(oat_file.c_str());
     int64_t vdex_size = OS::GetFileSizeBytes(vdex_file.c_str());
@@ -188,88 +184,9 @@
     ret.art_size = art_size;
     ret.oat_size = oat_size;
     ret.vdex_size = vdex_size;
-    scratch.Close();
-    // Clear image files since we compile the image multiple times and don't want to leave any
-    // artifacts behind.
-    ClearDirectory(scratch_dir.c_str(), /*recursive=*/ false);
     return ret;
   }
 
-  bool CompileBootImage(const std::vector<std::string>& extra_args,
-                        const std::string& image_file_name_prefix,
-                        ArrayRef<const std::string> dex_files,
-                        std::string* error_msg,
-                        const std::string& use_fd_prefix = "") {
-    Runtime* const runtime = Runtime::Current();
-    std::vector<std::string> argv;
-    argv.push_back(runtime->GetCompilerExecutable());
-    AddRuntimeArg(argv, "-Xms64m");
-    AddRuntimeArg(argv, "-Xmx64m");
-    for (const std::string& dex_file : dex_files) {
-      argv.push_back("--dex-file=" + dex_file);
-      argv.push_back("--dex-location=" + dex_file);
-    }
-    if (runtime->IsJavaDebuggable()) {
-      argv.push_back("--debuggable");
-    }
-    runtime->AddCurrentRuntimeFeaturesAsDex2OatArguments(&argv);
-
-    AddRuntimeArg(argv, "-Xverify:softfail");
-
-    if (!kIsTargetBuild) {
-      argv.push_back("--host");
-    }
-
-    std::unique_ptr<File> art_file;
-    std::unique_ptr<File> vdex_file;
-    std::unique_ptr<File> oat_file;
-    if (!use_fd_prefix.empty()) {
-      art_file.reset(OS::CreateEmptyFile((use_fd_prefix + ".art").c_str()));
-      vdex_file.reset(OS::CreateEmptyFile((use_fd_prefix + ".vdex").c_str()));
-      oat_file.reset(OS::CreateEmptyFile((use_fd_prefix + ".oat").c_str()));
-      argv.push_back("--image-fd=" + std::to_string(art_file->Fd()));
-      argv.push_back("--output-vdex-fd=" + std::to_string(vdex_file->Fd()));
-      argv.push_back("--oat-fd=" + std::to_string(oat_file->Fd()));
-      argv.push_back("--oat-location=" + image_file_name_prefix + ".oat");
-    } else {
-      argv.push_back("--image=" + image_file_name_prefix + ".art");
-      argv.push_back("--oat-file=" + image_file_name_prefix + ".oat");
-      argv.push_back("--oat-location=" + image_file_name_prefix + ".oat");
-    }
-
-    std::vector<std::string> compiler_options = runtime->GetCompilerOptions();
-    argv.insert(argv.end(), compiler_options.begin(), compiler_options.end());
-
-    // We must set --android-root.
-    const char* android_root = getenv("ANDROID_ROOT");
-    CHECK(android_root != nullptr);
-    argv.push_back("--android-root=" + std::string(android_root));
-    argv.insert(argv.end(), extra_args.begin(), extra_args.end());
-
-    bool result = RunDex2Oat(argv, error_msg);
-    if (art_file != nullptr) {
-      CHECK_EQ(0, art_file->FlushClose());
-    }
-    if (vdex_file != nullptr) {
-      CHECK_EQ(0, vdex_file->FlushClose());
-    }
-    if (oat_file != nullptr) {
-      CHECK_EQ(0, oat_file->FlushClose());
-    }
-    return result;
-  }
-
-  bool RunDex2Oat(const std::vector<std::string>& args, std::string* error_msg) {
-    // We only want fatal logging for the error message.
-    auto post_fork_fn = []() { return setenv("ANDROID_LOG_TAGS", "*:f", 1) == 0; };
-    ForkAndExecResult res = ForkAndExec(args, post_fork_fn, error_msg);
-    if (res.stage != ForkAndExecResult::kFinished) {
-      *error_msg = strerror(errno);
-      return false;
-    }
-    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.
@@ -293,6 +210,7 @@
     CHECK(EndsWith(dir, "/"));
     for (std::string& dex_file : *dex_files) {
       size_t slash_pos = dex_file.rfind('/');
+      CHECK(OS::FileExists(dex_file.c_str())) << dex_file;
       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);
@@ -415,13 +333,10 @@
   MemMap reservation = ReserveCoreImageAddressSpace(&error_msg);
   ASSERT_TRUE(reservation.IsValid()) << error_msg;
 
-  ScratchFile scratch;
-  std::string scratch_dir = scratch.GetFilename() + "-d";
-  int mkdir_result = mkdir(scratch_dir.c_str(), 0700);
-  ASSERT_EQ(0, mkdir_result);
-  scratch_dir += '/';
+  ScratchDir scratch;
+  const std::string& scratch_dir = scratch.GetPath();
   std::string image_dir = scratch_dir + GetInstructionSetString(kRuntimeISA);
-  mkdir_result = mkdir(image_dir.c_str(), 0700);
+  int mkdir_result = mkdir(image_dir.c_str(), 0700);
   ASSERT_EQ(0, mkdir_result);
   std::string filename_prefix = image_dir + "/core";
 
@@ -824,10 +739,6 @@
 
     DisableImageDex2Oat();
   }
-
-  ClearDirectory(scratch_dir.c_str());
-  int rmdir_result = rmdir(scratch_dir.c_str());
-  ASSERT_EQ(0, rmdir_result);
 }
 
 }  // namespace art
diff --git a/dexlayout/dexdiag_test.cc b/dexlayout/dexdiag_test.cc
index 9cf0f07..27ac402 100644
--- a/dexlayout/dexdiag_test.cc
+++ b/dexlayout/dexdiag_test.cc
@@ -25,7 +25,7 @@
 
 namespace art {
 
-static const char* kDexDiagContains = "--contains=core.vdex";
+static const char* kDexDiagContains = "--contains=boot.vdex";
 static const char* kDexDiagContainsFails = "--contains=anything_other_than_core.vdex";
 static const char* kDexDiagHelp = "--help";
 static const char* kDexDiagVerbose = "--verbose";
diff --git a/libartbase/base/common_art_test.cc b/libartbase/base/common_art_test.cc
index 7101ca4..978f69c 100644
--- a/libartbase/base/common_art_test.cc
+++ b/libartbase/base/common_art_test.cc
@@ -19,6 +19,7 @@
 #include <dirent.h>
 #include <dlfcn.h>
 #include <fcntl.h>
+#include <ftw.h>
 #include <stdlib.h>
 #include <unistd.h>
 #include <cstdio>
@@ -51,6 +52,29 @@
 
 using android::base::StringPrintf;
 
+ScratchDir::ScratchDir() {
+  // ANDROID_DATA needs to be set
+  CHECK_NE(static_cast<char*>(nullptr), getenv("ANDROID_DATA")) <<
+      "Are you subclassing RuntimeTest?";
+  path_ = getenv("ANDROID_DATA");
+  path_ += "/tmp-XXXXXX";
+  bool ok = (mkdtemp(&path_[0]) != nullptr);
+  CHECK(ok) << strerror(errno) << " for " << path_;
+  path_ += "/";
+}
+
+ScratchDir::~ScratchDir() {
+  // Recursively delete the directory and all its content.
+  nftw(path_.c_str(), [](const char* name, const struct stat*, int type, struct FTW *) {
+    if (type == FTW_F) {
+      unlink(name);
+    } else if (type == FTW_DP) {
+      rmdir(name);
+    }
+    return 0;
+  }, 256 /* max open file descriptors */, FTW_DEPTH);
+}
+
 ScratchFile::ScratchFile() {
   // ANDROID_DATA needs to be set
   CHECK_NE(static_cast<char*>(nullptr), getenv("ANDROID_DATA")) <<
@@ -364,13 +388,13 @@
 }
 
 static std::string GetDexFileName(const std::string& jar_prefix, bool host) {
-  std::string path = GetAndroidRoot();
-
-  std::string suffix = host
-      ? "-hostdex"                 // The host version.
-      : "-testdex";                // The unstripped target version.
-
-  return StringPrintf("%s/framework/%s%s.jar", path.c_str(), jar_prefix.c_str(), suffix.c_str());
+  if (host) {
+    std::string path = GetAndroidRoot();
+    return StringPrintf("%s/framework/%s-hostdex.jar", path.c_str(), jar_prefix.c_str());
+  } else {
+    const char* apex = (jar_prefix == "conscrypt") ? "com.android.conscrypt" : "com.android.art";
+    return StringPrintf("/apex/%s/javalib/%s.jar", apex, jar_prefix.c_str());
+  }
 }
 
 std::vector<std::string> CommonArtTestImpl::GetLibCoreModuleNames() const {
@@ -504,7 +528,7 @@
     std::string host_dir = GetAndroidRoot();
     location = StringPrintf("%s/framework/core.%s", host_dir.c_str(), suffix);
   } else {
-    location = StringPrintf("/data/art-test/core.%s", suffix);
+    location = StringPrintf("/apex/com.android.art/javalib/boot.%s", suffix);
   }
 
   return location;
diff --git a/libartbase/base/common_art_test.h b/libartbase/base/common_art_test.h
index 41af711..8d2693f 100644
--- a/libartbase/base/common_art_test.h
+++ b/libartbase/base/common_art_test.h
@@ -42,6 +42,22 @@
 
 class DexFile;
 
+class ScratchDir {
+ public:
+  ScratchDir();
+
+  ~ScratchDir();
+
+  const std::string& GetPath() const {
+    return path_;
+  }
+
+ private:
+  std::string path_;
+
+  DISALLOW_COPY_AND_ASSIGN(ScratchDir);
+};
+
 class ScratchFile {
  public:
   ScratchFile();
diff --git a/runtime/common_runtime_test.cc b/runtime/common_runtime_test.cc
index 135dc7b..64d2503 100644
--- a/runtime/common_runtime_test.cc
+++ b/runtime/common_runtime_test.cc
@@ -433,22 +433,106 @@
   return true;
 }
 
+bool CommonRuntimeTestImpl::CompileBootImage(const std::vector<std::string>& extra_args,
+                                             const std::string& image_file_name_prefix,
+                                             ArrayRef<const std::string> dex_files,
+                                             ArrayRef<const std::string> dex_locations,
+                                             std::string* error_msg,
+                                             const std::string& use_fd_prefix) {
+  Runtime* const runtime = Runtime::Current();
+  std::vector<std::string> argv {
+    runtime->GetCompilerExecutable(),
+    "--runtime-arg",
+    "-Xms64m",
+    "--runtime-arg",
+    "-Xmx64m",
+    "--runtime-arg",
+    "-Xverify:softfail",
+  };
+  CHECK_EQ(dex_files.size(), dex_locations.size());
+  for (const std::string& dex_file : dex_files) {
+    argv.push_back("--dex-file=" + dex_file);
+  }
+  for (const std::string& dex_location : dex_locations) {
+    argv.push_back("--dex-location=" + dex_location);
+  }
+  if (runtime->IsJavaDebuggable()) {
+    argv.push_back("--debuggable");
+  }
+  runtime->AddCurrentRuntimeFeaturesAsDex2OatArguments(&argv);
+
+  if (!kIsTargetBuild) {
+    argv.push_back("--host");
+  }
+
+  std::unique_ptr<File> art_file;
+  std::unique_ptr<File> vdex_file;
+  std::unique_ptr<File> oat_file;
+  if (!use_fd_prefix.empty()) {
+    art_file.reset(OS::CreateEmptyFile((use_fd_prefix + ".art").c_str()));
+    vdex_file.reset(OS::CreateEmptyFile((use_fd_prefix + ".vdex").c_str()));
+    oat_file.reset(OS::CreateEmptyFile((use_fd_prefix + ".oat").c_str()));
+    argv.push_back("--image-fd=" + std::to_string(art_file->Fd()));
+    argv.push_back("--output-vdex-fd=" + std::to_string(vdex_file->Fd()));
+    argv.push_back("--oat-fd=" + std::to_string(oat_file->Fd()));
+    argv.push_back("--oat-location=" + image_file_name_prefix + ".oat");
+  } else {
+    argv.push_back("--image=" + image_file_name_prefix + ".art");
+    argv.push_back("--oat-file=" + image_file_name_prefix + ".oat");
+    argv.push_back("--oat-location=" + image_file_name_prefix + ".oat");
+  }
+
+  std::vector<std::string> compiler_options = runtime->GetCompilerOptions();
+  argv.insert(argv.end(), compiler_options.begin(), compiler_options.end());
+
+  // We must set --android-root.
+  const char* android_root = getenv("ANDROID_ROOT");
+  CHECK(android_root != nullptr);
+  argv.push_back("--android-root=" + std::string(android_root));
+  argv.insert(argv.end(), extra_args.begin(), extra_args.end());
+
+  bool result = RunDex2Oat(argv, error_msg);
+  if (art_file != nullptr) {
+    CHECK_EQ(0, art_file->FlushClose());
+  }
+  if (vdex_file != nullptr) {
+    CHECK_EQ(0, vdex_file->FlushClose());
+  }
+  if (oat_file != nullptr) {
+    CHECK_EQ(0, oat_file->FlushClose());
+  }
+  return result;
+}
+
+bool CommonRuntimeTestImpl::RunDex2Oat(const std::vector<std::string>& args,
+                                       std::string* error_msg) {
+  // We only want fatal logging for the error message.
+  auto post_fork_fn = []() { return setenv("ANDROID_LOG_TAGS", "*:f", 1) == 0; };
+  ForkAndExecResult res = ForkAndExec(args, post_fork_fn, error_msg);
+  if (res.stage != ForkAndExecResult::kFinished) {
+    *error_msg = strerror(errno);
+    return false;
+  }
+  return res.StandardSuccess();
+}
+
 std::string CommonRuntimeTestImpl::GetImageDirectory() {
   if (IsHost()) {
     const char* host_dir = getenv("ANDROID_HOST_OUT");
     CHECK(host_dir != nullptr);
     return std::string(host_dir) + "/framework";
   } else {
-    return std::string("/data/art-test");
+    return std::string("/apex/com.android.art/javalib");
   }
 }
 
 std::string CommonRuntimeTestImpl::GetImageLocation() {
-  return GetImageDirectory() + "/core.art";
+  return GetImageDirectory() + (IsHost() ? "/core.art" : "/boot.art");
 }
 
 std::string CommonRuntimeTestImpl::GetSystemImageFile() {
-  return GetImageDirectory() + "/" + GetInstructionSetString(kRuntimeISA) + "/core.art";
+  std::string isa = GetInstructionSetString(kRuntimeISA);
+  return GetImageDirectory() + "/" + isa + (IsHost() ? "/core.art" : "/boot.art");
 }
 
 void CommonRuntimeTestImpl::EnterTransactionMode() {
diff --git a/runtime/common_runtime_test.h b/runtime/common_runtime_test.h
index c87d317..2e9e078 100644
--- a/runtime/common_runtime_test.h
+++ b/runtime/common_runtime_test.h
@@ -113,6 +113,24 @@
   bool StartDex2OatCommandLine(/*out*/std::vector<std::string>* argv,
                                /*out*/std::string* error_msg);
 
+  bool CompileBootImage(const std::vector<std::string>& extra_args,
+                        const std::string& image_file_name_prefix,
+                        ArrayRef<const std::string> dex_files,
+                        ArrayRef<const std::string> dex_locations,
+                        std::string* error_msg,
+                        const std::string& use_fd_prefix = "");
+
+  bool CompileBootImage(const std::vector<std::string>& extra_args,
+                        const std::string& image_file_name_prefix,
+                        ArrayRef<const std::string> dex_files,
+                        std::string* error_msg,
+                        const std::string& use_fd_prefix = "") {
+    return CompileBootImage(
+        extra_args, image_file_name_prefix, dex_files, dex_files, error_msg, use_fd_prefix);
+  }
+
+  bool RunDex2Oat(const std::vector<std::string>& args, std::string* error_msg);
+
  protected:
   // Allow subclases such as CommonCompilerTest to add extra options.
   virtual void SetUpRuntimeOptions(RuntimeOptions* options ATTRIBUTE_UNUSED) {}
diff --git a/runtime/dex2oat_environment_test.h b/runtime/dex2oat_environment_test.h
index 0d74dbb..fb8a760 100644
--- a/runtime/dex2oat_environment_test.h
+++ b/runtime/dex2oat_environment_test.h
@@ -137,13 +137,6 @@
     dst_stream << src_stream.rdbuf();
   }
 
-  // Returns the path to an image location whose contents differ from the
-  // image at GetImageLocation(). This is used for testing mismatched
-  // image checksums in the oat_file_assistant_tests.
-  std::string GetImageLocation2() const {
-    return GetImageDirectory() + "/core-interpreter.art";
-  }
-
   std::string GetDexSrc1() const {
     return GetTestDexFileName("Main");
   }
diff --git a/runtime/dexopt_test.cc b/runtime/dexopt_test.cc
index afbd053..8ba6f3e 100644
--- a/runtime/dexopt_test.cc
+++ b/runtime/dexopt_test.cc
@@ -69,6 +69,28 @@
   return Exec(argv, error_msg);
 }
 
+std::string DexoptTest::GenerateAlternateImage(const std::string& scratch_dir) {
+  std::vector<std::string> libcore_dex_files = GetLibCoreDexFileNames();
+  std::vector<std::string> libcore_dex_locations = GetLibCoreDexLocations();
+
+  std::string image_dir = scratch_dir + GetInstructionSetString(kRuntimeISA);
+  int mkdir_result = mkdir(image_dir.c_str(), 0700);
+  CHECK_EQ(0, mkdir_result) << image_dir.c_str();
+
+  std::vector<std::string> extra_args {
+    "--compiler-filter=verify",
+    android::base::StringPrintf("--base=0x%08x", ART_BASE_ADDRESS),
+  };
+  std::string filename_prefix = image_dir + "/boot-interpreter";
+  ArrayRef<const std::string> dex_files(libcore_dex_files);
+  ArrayRef<const std::string> dex_locations(libcore_dex_locations);
+  std::string error_msg;
+  bool ok = CompileBootImage(extra_args, filename_prefix, dex_files, dex_locations, &error_msg);
+  EXPECT_TRUE(ok) << error_msg;
+
+  return scratch_dir + "boot-interpreter.art";
+}
+
 void DexoptTest::GenerateOatForTest(const std::string& dex_location,
                                     const std::string& oat_location,
                                     CompilerFilter::Filter filter,
@@ -92,8 +114,11 @@
   }
 
   std::string image_location = GetImageLocation();
+  std::optional<ScratchDir> scratch;
   if (with_alternate_image) {
-    args.push_back("--boot-image=" + GetImageLocation2());
+    scratch.emplace();  // Create the scratch directory for the generated boot image.
+    std::string alternate_image_location = GenerateAlternateImage(scratch->GetPath());
+    args.push_back("--boot-image=" + alternate_image_location);
   }
 
   if (compilation_reason != nullptr) {
diff --git a/runtime/dexopt_test.h b/runtime/dexopt_test.h
index bfae8a1..a236393 100644
--- a/runtime/dexopt_test.h
+++ b/runtime/dexopt_test.h
@@ -32,6 +32,8 @@
 
   void PostRuntimeCreate() override;
 
+  std::string GenerateAlternateImage(const std::string& scratch_dir);
+
   // Generate an oat file for the purposes of test.
   // The oat file will be generated for dex_location in the given oat_location
   // with the following configuration:
diff --git a/tools/buildbot-sync.sh b/tools/buildbot-sync.sh
index 705d88a..4c718ee 100755
--- a/tools/buildbot-sync.sh
+++ b/tools/buildbot-sync.sh
@@ -173,6 +173,7 @@
 activate_apex com.android.i18n
 activate_apex com.android.runtime
 activate_apex com.android.tzdata
+activate_apex com.android.conscrypt
 
 # Adjust the linker configuration file (if needed).
 #