Add artd unit tests.

This change adds `art_artd_tests`, which contains the unit tests of
artd. The change also splits the code into artd.h/artd.cc and
artd_main.cc, where artd.h/artd.cc contains the implementation that is
unit-testable, while artd_main.cc contains the main function of the artd
binary.

Bug: 177273468
Test: m test-art-host-gtest-art_artd_tests
Test: ArtGtestsTargetChroot:ArtdTest
Ignore-AOSP-First: Will cherry-pick later.
Change-Id: I19701d7ca83f541becdcd413e740eff93d03037d
diff --git a/artd/Android.bp b/artd/Android.bp
index e69483a..7f99685 100644
--- a/artd/Android.bp
+++ b/artd/Android.bp
@@ -22,23 +22,32 @@
     default_applicable_licenses: ["art_license"],
 }
 
-art_cc_binary {
-    name: "artd",
+cc_defaults {
+    name: "artd_defaults",
     defaults: ["art_defaults"],
-
     srcs: [
         "artd.cc",
     ],
-
     shared_libs: [
-        "artd-aidl-ndk",
-        "libart",
-        "libartbase",
         "libarttools",
         "libbase",
         "libbinder_ndk",
     ],
+    static_libs: [
+        "artd-aidl-ndk",
+    ],
+}
 
+art_cc_binary {
+    name: "artd",
+    defaults: ["artd_defaults"],
+    srcs: [
+        "artd_main.cc",
+    ],
+    shared_libs: [
+        "libart",
+        "libartbase",
+    ],
     apex_available: [
         "com.android.art",
         "com.android.art.debug",
@@ -51,3 +60,35 @@
     filename: "init.rc",
     installable: false,
 }
+
+art_cc_defaults {
+    name: "art_artd_tests_defaults",
+    defaults: ["artd_defaults"],
+    // TODO(b/235464166): The host test does not build on master-art because of
+    // the dependency on libbinder_ndk.
+    host_supported: false,
+    srcs: [
+        "artd_test.cc",
+    ],
+}
+
+// Version of ART gtest `art_artd_tests` bundled with the ART APEX on target.
+// TODO(b/192274705): Remove this module when the migration to standalone ART
+// gtests is complete.
+art_cc_test {
+    name: "art_artd_tests",
+    defaults: [
+        "art_gtest_defaults",
+        "art_artd_tests_defaults",
+    ],
+}
+
+// Standalone version of ART gtest `art_artd_tests`, not bundled with the ART
+// APEX on target.
+art_cc_test {
+    name: "art_standalone_artd_tests",
+    defaults: [
+        "art_standalone_gtest_defaults",
+        "art_artd_tests_defaults",
+    ],
+}
diff --git a/artd/artd.cc b/artd/artd.cc
index a8c6084..98693cb 100644
--- a/artd/artd.cc
+++ b/artd/artd.cc
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#include "artd.h"
+
 #include <stdlib.h>
 #include <unistd.h>
 
@@ -43,7 +45,6 @@
 namespace {
 
 using ::aidl::com::android::server::art::ArtifactsPath;
-using ::aidl::com::android::server::art::BnArtd;
 using ::aidl::com::android::server::art::GetOptimizationStatusResult;
 using ::android::base::Error;
 using ::android::base::GetBoolProperty;
@@ -51,6 +52,8 @@
 using ::android::base::Split;
 using ::ndk::ScopedAStatus;
 
+constexpr const char* kServiceName = "artd";
+
 constexpr const char* kPhenotypeFlagPrefix = "persist.device_config.runtime_native_boot.";
 constexpr const char* kDalvikVmFlagPrefix = "dalvik.vm.";
 
@@ -91,128 +94,94 @@
 
 }  // namespace
 
-class Artd : public BnArtd {
-  constexpr static const char* kServiceName = "artd";
+ScopedAStatus Artd::isAlive(bool* _aidl_return) {
+  *_aidl_return = true;
+  return ScopedAStatus::ok();
+}
 
- public:
-  ScopedAStatus isAlive(bool* _aidl_return) override {
-    *_aidl_return = true;
-    return ScopedAStatus::ok();
+ScopedAStatus Artd::deleteArtifacts(const ArtifactsPath& in_artifactsPath, int64_t* _aidl_return) {
+  (void)in_artifactsPath;
+  (void)_aidl_return;
+  return ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+}
+
+ScopedAStatus Artd::getOptimizationStatus(const std::string& in_dexFile,
+                                          const std::string& in_instructionSet,
+                                          const std::string& in_classLoaderContext,
+                                          GetOptimizationStatusResult* _aidl_return) {
+  Result<OatFileAssistant::RuntimeOptions> runtime_options = GetRuntimeOptions();
+  if (!runtime_options.ok()) {
+    return ScopedAStatus::fromExceptionCodeWithMessage(
+        EX_ILLEGAL_STATE,
+        ("Failed to get runtime options: " + runtime_options.error().message()).c_str());
   }
 
-  ScopedAStatus deleteArtifacts(const ArtifactsPath& in_artifactsPath,
-                                int64_t* _aidl_return) override {
-    (void)in_artifactsPath;
-    (void)_aidl_return;
-    return ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+  std::string error_msg;
+  if (!OatFileAssistant::GetOptimizationStatus(
+          in_dexFile.c_str(),
+          in_instructionSet.c_str(),
+          in_classLoaderContext.c_str(),
+          std::make_unique<OatFileAssistant::RuntimeOptions>(std::move(*runtime_options)),
+          &_aidl_return->compilerFilter,
+          &_aidl_return->compilationReason,
+          &_aidl_return->locationDebugString,
+          &error_msg)) {
+    return ScopedAStatus::fromExceptionCodeWithMessage(
+        EX_ILLEGAL_STATE, ("Failed to get optimization status: " + error_msg).c_str());
   }
 
-  ScopedAStatus getOptimizationStatus(const std::string& in_dexFile,
-                                      const std::string& in_instructionSet,
-                                      const std::string& in_classLoaderContext,
-                                      GetOptimizationStatusResult* _aidl_return) override {
-    Result<OatFileAssistant::RuntimeOptions> runtime_options = GetRuntimeOptions();
-    if (!runtime_options.ok()) {
-      return ScopedAStatus::fromExceptionCodeWithMessage(
-          EX_ILLEGAL_STATE,
-          ("Failed to get runtime options: " + runtime_options.error().message()).c_str());
-    }
+  return ScopedAStatus::ok();
+}
 
-    std::string error_msg;
-    if (!OatFileAssistant::GetOptimizationStatus(
-            in_dexFile.c_str(),
-            in_instructionSet.c_str(),
-            in_classLoaderContext.c_str(),
-            std::make_unique<OatFileAssistant::RuntimeOptions>(std::move(*runtime_options)),
-            &_aidl_return->compilerFilter,
-            &_aidl_return->compilationReason,
-            &_aidl_return->locationDebugString,
-            &error_msg)) {
-      return ScopedAStatus::fromExceptionCodeWithMessage(
-          EX_ILLEGAL_STATE, ("Failed to get optimization status: " + error_msg).c_str());
-    }
-
-    return ScopedAStatus::ok();
+Result<void> Artd::Start() {
+  ScopedAStatus status = ScopedAStatus::fromStatus(
+      AServiceManager_registerLazyService(this->asBinder().get(), kServiceName));
+  if (!status.isOk()) {
+    return Error() << status.getDescription();
   }
 
-  Result<void> Start() {
-    LOG(INFO) << "Starting artd";
+  ABinderProcess_startThreadPool();
 
-    ScopedAStatus status = ScopedAStatus::fromStatus(
-        AServiceManager_registerLazyService(this->asBinder().get(), kServiceName));
-    if (!status.isOk()) {
-      return Error() << status.getDescription();
-    }
+  return {};
+}
 
-    ABinderProcess_startThreadPool();
+Result<OatFileAssistant::RuntimeOptions> Artd::GetRuntimeOptions() {
+  // We don't cache this system property because it can change.
+  bool use_jit_zygote = UseJitZygote();
 
-    return {};
+  if (!HasRuntimeOptionsCache()) {
+    OR_RETURN(BuildRuntimeOptionsCache());
   }
 
- private:
-  Result<OatFileAssistant::RuntimeOptions> GetRuntimeOptions() {
-    // We don't cache this system property because it can change.
-    bool use_jit_zygote = UseJitZygote();
+  return OatFileAssistant::RuntimeOptions{
+      .image_locations = cached_boot_image_locations_,
+      .boot_class_path = cached_boot_class_path_,
+      .boot_class_path_locations = cached_boot_class_path_,
+      .use_jit_zygote = use_jit_zygote,
+      .deny_art_apex_data_files = cached_deny_art_apex_data_files_,
+      .apex_versions = cached_apex_versions_,
+  };
+}
 
-    if (!HasRuntimeOptionsCache()) {
-      OR_RETURN(BuildRuntimeOptionsCache());
-    }
+Result<void> Artd::BuildRuntimeOptionsCache() {
+  // This system property can only be set by odsign on boot, so it won't change.
+  bool deny_art_apex_data_files = DenyArtApexDataFiles();
 
-    return OatFileAssistant::RuntimeOptions{
-        .image_locations = cached_boot_image_locations_,
-        .boot_class_path = cached_boot_class_path_,
-        .boot_class_path_locations = cached_boot_class_path_,
-        .use_jit_zygote = use_jit_zygote,
-        .deny_art_apex_data_files = cached_deny_art_apex_data_files_,
-        .apex_versions = cached_apex_versions_,
-    };
-  }
+  std::vector<std::string> image_locations =
+      OR_RETURN(GetBootImageLocations(deny_art_apex_data_files));
+  std::vector<std::string> boot_class_path = OR_RETURN(GetBootClassPath());
+  std::string apex_versions =
+      Runtime::GetApexVersions(ArrayRef<const std::string>(boot_class_path));
 
-  Result<void> BuildRuntimeOptionsCache() {
-    // This system property can only be set by odsign on boot, so it won't change.
-    bool deny_art_apex_data_files = DenyArtApexDataFiles();
+  cached_boot_image_locations_ = std::move(image_locations);
+  cached_boot_class_path_ = std::move(boot_class_path);
+  cached_apex_versions_ = std::move(apex_versions);
+  cached_deny_art_apex_data_files_ = deny_art_apex_data_files;
 
-    std::vector<std::string> image_locations =
-        OR_RETURN(GetBootImageLocations(deny_art_apex_data_files));
-    std::vector<std::string> boot_class_path = OR_RETURN(GetBootClassPath());
-    std::string apex_versions =
-        Runtime::GetApexVersions(ArrayRef<const std::string>(boot_class_path));
+  return {};
+}
 
-    cached_boot_image_locations_ = std::move(image_locations);
-    cached_boot_class_path_ = std::move(boot_class_path);
-    cached_apex_versions_ = std::move(apex_versions);
-    cached_deny_art_apex_data_files_ = deny_art_apex_data_files;
-
-    return {};
-  }
-
-  bool HasRuntimeOptionsCache() {
-    return !cached_boot_image_locations_.empty();
-  }
-
-  std::vector<std::string> cached_boot_image_locations_;
-  std::vector<std::string> cached_boot_class_path_;
-  std::string cached_apex_versions_;
-  bool cached_deny_art_apex_data_files_;
-};
+bool Artd::HasRuntimeOptionsCache() const { return !cached_boot_image_locations_.empty(); }
 
 }  // namespace artd
 }  // namespace art
-
-int main(const int argc __attribute__((unused)), char* argv[]) {
-  setenv("ANDROID_LOG_TAGS", "*:v", 1);
-  android::base::InitLogging(argv);
-
-  art::artd::Artd artd;
-
-  if (auto ret = artd.Start(); !ret.ok()) {
-    LOG(ERROR) << "Unable to start artd: " << ret.error();
-    exit(1);
-  }
-
-  ABinderProcess_joinThreadPool();
-
-  LOG(INFO) << "artd shutting down";
-
-  return 0;
-}
diff --git a/artd/artd.h b/artd/artd.h
new file mode 100644
index 0000000..2a05267
--- /dev/null
+++ b/artd/artd.h
@@ -0,0 +1,63 @@
+/*
+ * 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_ARTD_ARTD_H_
+#define ART_ARTD_ARTD_H_
+
+#include <string>
+#include <vector>
+
+#include "aidl/com/android/server/art/BnArtd.h"
+#include "android-base/result.h"
+#include "android/binder_auto_utils.h"
+#include "oat_file_assistant.h"
+
+namespace art {
+namespace artd {
+
+class Artd : public aidl::com::android::server::art::BnArtd {
+ public:
+  ndk::ScopedAStatus isAlive(bool* _aidl_return) override;
+
+  ndk::ScopedAStatus deleteArtifacts(
+      const aidl::com::android::server::art::ArtifactsPath& in_artifactsPath,
+      int64_t* _aidl_return) override;
+
+  ndk::ScopedAStatus getOptimizationStatus(
+      const std::string& in_dexFile,
+      const std::string& in_instructionSet,
+      const std::string& in_classLoaderContext,
+      aidl::com::android::server::art::GetOptimizationStatusResult* _aidl_return) override;
+
+  android::base::Result<void> Start();
+
+ private:
+  android::base::Result<OatFileAssistant::RuntimeOptions> GetRuntimeOptions();
+
+  android::base::Result<void> BuildRuntimeOptionsCache();
+
+  bool HasRuntimeOptionsCache() const;
+
+  std::vector<std::string> cached_boot_image_locations_;
+  std::vector<std::string> cached_boot_class_path_;
+  std::string cached_apex_versions_;
+  bool cached_deny_art_apex_data_files_;
+};
+
+}  // namespace artd
+}  // namespace art
+
+#endif  // ART_ARTD_ARTD_H_
diff --git a/artd/artd_main.cc b/artd/artd_main.cc
new file mode 100644
index 0000000..3644eba
--- /dev/null
+++ b/artd/artd_main.cc
@@ -0,0 +1,42 @@
+/*
+ * 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 <stdlib.h>
+
+#include "android-base/logging.h"
+#include "android-base/macros.h"
+#include "android/binder_interface_utils.h"
+#include "android/binder_process.h"
+#include "artd.h"
+
+int main(int argc ATTRIBUTE_UNUSED, char* argv[]) {
+  android::base::InitLogging(argv);
+
+  auto artd = ndk::SharedRefBase::make<art::artd::Artd>();
+
+  LOG(INFO) << "Starting artd";
+
+  if (auto ret = artd->Start(); !ret.ok()) {
+    LOG(ERROR) << "Unable to start artd: " << ret.error();
+    exit(1);
+  }
+
+  ABinderProcess_joinThreadPool();
+
+  LOG(INFO) << "artd shutting down";
+
+  return 0;
+}
diff --git a/artd/artd_test.cc b/artd/artd_test.cc
new file mode 100644
index 0000000..14bccc2
--- /dev/null
+++ b/artd/artd_test.cc
@@ -0,0 +1,49 @@
+/*
+ * 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 "artd.h"
+
+#include <memory>
+
+#include "android/binder_interface_utils.h"
+#include "base/common_art_test.h"
+#include "gtest/gtest.h"
+
+namespace art {
+namespace artd {
+namespace {
+
+class ArtdTest : public CommonArtTest {
+ protected:
+  void SetUp() override {
+    CommonArtTest::SetUp();
+    artd_ = ndk::SharedRefBase::make<Artd>();
+  }
+
+  void TearDown() override { CommonArtTest::TearDown(); }
+
+  std::shared_ptr<Artd> artd_;
+};
+
+TEST_F(ArtdTest, isAlive) {
+  bool result = false;
+  artd_->isAlive(&result);
+  EXPECT_TRUE(result);
+}
+
+}  // namespace
+}  // namespace artd
+}  // namespace art
diff --git a/build/Android.gtest.mk b/build/Android.gtest.mk
index d9a75e4..c9becd7 100644
--- a/build/Android.gtest.mk
+++ b/build/Android.gtest.mk
@@ -132,7 +132,10 @@
     art_runtime_tests \
     art_sigchain_tests \
 
-ART_TEST_MODULES_TARGET := $(ART_TEST_MODULES_COMMON) art_odrefresh_tests
+ART_TEST_MODULES_TARGET := $(ART_TEST_MODULES_COMMON) \
+    art_artd_tests \
+    art_odrefresh_tests \
+
 ART_TEST_MODULES_HOST := $(ART_TEST_MODULES_COMMON)
 
 ART_TARGET_GTEST_NAMES := $(foreach tm,$(ART_TEST_MODULES_TARGET),\
diff --git a/build/apex/Android.bp b/build/apex/Android.bp
index 890de9d..9ad5eee 100644
--- a/build/apex/Android.bp
+++ b/build/apex/Android.bp
@@ -400,6 +400,7 @@
 
 // ART gtests with dependencies on internal ART APEX libraries.
 art_gtests = [
+    "art_artd_tests",
     "art_cmdline_tests",
     "art_compiler_tests",
     "art_dex2oat_tests",
diff --git a/build/apex/art_apex_test.py b/build/apex/art_apex_test.py
index 556bb78..a13a7d3 100755
--- a/build/apex/art_apex_test.py
+++ b/build/apex/art_apex_test.py
@@ -558,7 +558,6 @@
     # Check internal libraries for ART.
     self._checker.check_native_library('libartservice')
     self._checker.check_native_library('libperfetto_hprof')
-    self._checker.check_prefer64_library('artd-aidl-ndk')
 
     # Check internal Java libraries
     self._checker.check_java_library("service-art")
@@ -672,6 +671,7 @@
 
   def run(self):
     # Check ART test binaries.
+    self._checker.check_art_test_executable('art_artd_tests')
     self._checker.check_art_test_executable('art_cmdline_tests')
     self._checker.check_art_test_executable('art_compiler_tests')
     self._checker.check_art_test_executable('art_dex2oat_tests')
diff --git a/test/utils/regen-test-files b/test/utils/regen-test-files
index 7ddffe6..1522758 100755
--- a/test/utils/regen-test-files
+++ b/test/utils/regen-test-files
@@ -215,6 +215,7 @@
 # ART gtests that do not need root access to the device.
 art_gtest_user_module_names = [
     "art_libnativebridge_cts_tests",
+    "art_standalone_artd_tests",
     "art_standalone_cmdline_tests",
     "art_standalone_compiler_tests",
     "art_standalone_dex2oat_tests",