Don't spin up the ART runtime in art_standalone_dex2oat_cts_tests.

It was mistakenly based on CommonRuntimeTest, which starts a runtime
through unstable APIs. The test should only run dex2oat with minimal
arguments to make --force-palette-compilation-hooks work.

Some refactoring in Dex2oatEnvironmentTest and CommonArtTest to
separate out the scratch directory creation code.

Test: atest Dex2oatCtsTest
  Check with temporary logging in
  system/libartpalette/palette_android_partner.cc that
  PaletteNotify(Start|End)Dex2oatCompilation still gets called.
Bug: 253937792
Change-Id: Ieaea0faeef9571c0a269d565acd105d0f74f3d13
diff --git a/dex2oat/dex2oat_cts_test.cc b/dex2oat/dex2oat_cts_test.cc
index 41c7015..2541264 100644
--- a/dex2oat/dex2oat_cts_test.cc
+++ b/dex2oat/dex2oat_cts_test.cc
@@ -14,11 +14,54 @@
  * limitations under the License.
  */
 
+#include "base/file_utils.h"
 #include "dex2oat_environment_test.h"
 
 namespace art {
 
-class Dex2oatCtsTest : public Dex2oatEnvironmentTest {};
+class Dex2oatCtsTest : public CommonArtTest, public Dex2oatScratchDirs {
+ public:
+  void SetUp() override {
+    CommonArtTest::SetUp();
+    Dex2oatScratchDirs::SetUp(android_data_);
+  }
+
+  void TearDown() override {
+    Dex2oatScratchDirs::TearDown();
+    CommonArtTest::TearDown();
+  }
+
+ protected:
+  // Stripped down counterpart to Dex2oatEnvironmentTest::Dex2Oat that only adds
+  // enough arguments for our purposes.
+  int Dex2Oat(const std::vector<std::string>& dex2oat_args,
+              std::string* output,
+              std::string* error_msg) {
+    // This command line should work regardless of bitness, ISA, etc.
+    std::vector<std::string> argv = {std::string(kAndroidArtApexDefaultPath) + "/bin/dex2oat"};
+    argv.insert(argv.end(), dex2oat_args.begin(), dex2oat_args.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));
+
+    // We need dex2oat to actually log things.
+    auto post_fork_fn = []() { return setenv("ANDROID_LOG_TAGS", "*:d", 1) == 0; };
+    ForkAndExecResult res = ForkAndExec(argv, post_fork_fn, output);
+    if (res.stage != ForkAndExecResult::kFinished) {
+      *error_msg = strerror(errno);
+      ::testing::AssertionFailure() << "Failed to finish dex2oat invocation: " << *error_msg;
+    }
+
+    if (!res.StandardSuccess()) {
+      // We cannot use ASSERT_TRUE since the method returns an int and not void.
+      ::testing::AssertionFailure() << "dex2oat fork/exec failed: " << *error_msg;
+    }
+
+    return res.status_code;
+  }
+};
 
 // Run dex2oat with --enable-palette-compilation-hooks to force calls to
 // PaletteNotify{Start,End}Dex2oatCompilation.
diff --git a/libartbase/base/common_art_test.h b/libartbase/base/common_art_test.h
index fccb217..f4935cc 100644
--- a/libartbase/base/common_art_test.h
+++ b/libartbase/base/common_art_test.h
@@ -146,6 +146,8 @@
 
   static void TearDownAndroidDataDir(const std::string& android_data, bool fail_on_error);
 
+  static void ClearDirectory(const char* dirpath, bool recursive = true);
+
   // Get the names of the libcore modules.
   virtual std::vector<std::string> GetLibCoreModuleNames() const;
 
@@ -238,8 +240,6 @@
 
   std::unique_ptr<const DexFile> LoadExpectSingleDexFile(const char* location);
 
-  void ClearDirectory(const char* dirpath, bool recursive = true);
-
   // Open a file (allows reading of framework jars).
   std::vector<std::unique_ptr<const DexFile>> OpenDexFiles(const char* filename);
 
diff --git a/runtime/dex2oat_environment_test.h b/runtime/dex2oat_environment_test.h
index 166464f..9ebc68d 100644
--- a/runtime/dex2oat_environment_test.h
+++ b/runtime/dex2oat_environment_test.h
@@ -41,21 +41,17 @@
 
 static constexpr bool kDebugArgs = false;
 
-// Test class that provides some helpers to set a test up for compilation using dex2oat.
-class Dex2oatEnvironmentTest : public CommonRuntimeTest {
+class Dex2oatScratchDirs {
  public:
-  void SetUp() override {
-    CommonRuntimeTest::SetUp();
-    const ArtDexFileLoader dex_file_loader;
-
+  void SetUp(const std::string& android_data) {
     // Create a scratch directory to work from.
 
     // Get the realpath of the android data. The oat dir should always point to real location
     // when generating oat files in dalvik-cache. This avoids complicating the unit tests
     // when matching the expected paths.
-    UniqueCPtr<const char[]> android_data_real(realpath(android_data_.c_str(), nullptr));
+    UniqueCPtr<const char[]> android_data_real(realpath(android_data.c_str(), nullptr));
     ASSERT_TRUE(android_data_real != nullptr)
-      << "Could not get the realpath of the android data" << android_data_ << strerror(errno);
+        << "Could not get the realpath of the android data" << android_data << strerror(errno);
 
     scratch_dir_.assign(android_data_real.get());
     scratch_dir_ += "/Dex2oatEnvironmentTest";
@@ -67,6 +63,41 @@
 
     odex_dir_ = odex_oat_dir_ + "/" + std::string(GetInstructionSetString(kRuntimeISA));
     ASSERT_EQ(0, mkdir(odex_dir_.c_str(), 0700));
+  }
+
+  void TearDown() {
+    CommonArtTest::ClearDirectory(odex_dir_.c_str());
+    ASSERT_EQ(0, rmdir(odex_dir_.c_str()));
+
+    CommonArtTest::ClearDirectory(odex_oat_dir_.c_str());
+    ASSERT_EQ(0, rmdir(odex_oat_dir_.c_str()));
+
+    CommonArtTest::ClearDirectory(scratch_dir_.c_str());
+    ASSERT_EQ(0, rmdir(scratch_dir_.c_str()));
+  }
+
+  // Scratch directory, for dex and odex files (oat files will go in the
+  // dalvik cache).
+  const std::string& GetScratchDir() const { return scratch_dir_; }
+
+  // Odex directory is the subdirectory in the scratch directory where odex
+  // files should be located.
+  const std::string& GetOdexDir() const { return odex_dir_; }
+
+ private:
+  std::string scratch_dir_;
+  std::string odex_oat_dir_;
+  std::string odex_dir_;
+};
+
+// Test class that provides some helpers to set a test up for compilation using dex2oat.
+class Dex2oatEnvironmentTest : public Dex2oatScratchDirs, public CommonRuntimeTest {
+ public:
+  void SetUp() override {
+    CommonRuntimeTest::SetUp();
+    Dex2oatScratchDirs::SetUp(android_data_);
+
+    const ArtDexFileLoader dex_file_loader;
 
     // Verify the environment is as we expect
     std::vector<uint32_t> checksums;
@@ -122,15 +153,7 @@
   }
 
   void TearDown() override {
-    ClearDirectory(odex_dir_.c_str());
-    ASSERT_EQ(0, rmdir(odex_dir_.c_str()));
-
-    ClearDirectory(odex_oat_dir_.c_str());
-    ASSERT_EQ(0, rmdir(odex_oat_dir_.c_str()));
-
-    ClearDirectory(scratch_dir_.c_str());
-    ASSERT_EQ(0, rmdir(scratch_dir_.c_str()));
-
+    Dex2oatScratchDirs::TearDown();
     CommonRuntimeTest::TearDown();
   }
 
@@ -165,18 +188,6 @@
     return GetTestDexFileName("Nested");
   }
 
-  // Scratch directory, for dex and odex files (oat files will go in the
-  // dalvik cache).
-  const std::string& GetScratchDir() const {
-    return scratch_dir_;
-  }
-
-  // Odex directory is the subdirectory in the scratch directory where odex
-  // files should be located.
-  const std::string& GetOdexDir() const {
-    return odex_dir_;
-  }
-
   int Dex2Oat(const std::vector<std::string>& dex2oat_args,
               std::string* output,
               std::string* error_msg) {
@@ -249,11 +260,6 @@
     fflush(file);
     fclose(file);
   }
-
- private:
-  std::string scratch_dir_;
-  std::string odex_oat_dir_;
-  std::string odex_dir_;
 };
 
 }  // namespace art