artd: get optimization status.

Also:
- Switch to the real artd in ART Serivces.

Bug: 233383589
Test: -
  1. adb shell pm art get-optimization-status com.google.android.youtube
  2. See the following output.
     dexFile = "/product/app/YouTube/YouTube.apk", instructionSet = "x86_64", compilerFilter = "verify", compilationReason = "vdex", locationDebugString = "/product/app/YouTube/oat/x86_64/YouTube.vdex"
Ignore-AOSP-First: ART Services
Change-Id: I32d6f6e235441f526dcea0672a5575252b77fe6c
diff --git a/artd/Android.bp b/artd/Android.bp
index 6db1287..e69483a 100644
--- a/artd/Android.bp
+++ b/artd/Android.bp
@@ -32,6 +32,7 @@
 
     shared_libs: [
         "artd-aidl-ndk",
+        "libart",
         "libartbase",
         "libarttools",
         "libbase",
diff --git a/artd/artd.cc b/artd/artd.cc
index 89b9421..a8c6084 100644
--- a/artd/artd.cc
+++ b/artd/artd.cc
@@ -14,16 +14,27 @@
  * limitations under the License.
  */
 
+#include <stdlib.h>
 #include <unistd.h>
 
+#include <memory>
 #include <string>
+#include <utility>
+#include <vector>
 
 #include "aidl/com/android/server/art/BnArtd.h"
+#include "android-base/errors.h"
 #include "android-base/logging.h"
+#include "android-base/properties.h"
 #include "android-base/result.h"
+#include "android-base/strings.h"
 #include "android/binder_auto_utils.h"
 #include "android/binder_manager.h"
 #include "android/binder_process.h"
+#include "base/array_ref.h"
+#include "base/file_utils.h"
+#include "oat_file_assistant.h"
+#include "runtime.h"
 #include "tools/tools.h"
 
 namespace art {
@@ -35,9 +46,49 @@
 using ::aidl::com::android::server::art::BnArtd;
 using ::aidl::com::android::server::art::GetOptimizationStatusResult;
 using ::android::base::Error;
+using ::android::base::GetBoolProperty;
 using ::android::base::Result;
+using ::android::base::Split;
 using ::ndk::ScopedAStatus;
 
+constexpr const char* kPhenotypeFlagPrefix = "persist.device_config.runtime_native_boot.";
+constexpr const char* kDalvikVmFlagPrefix = "dalvik.vm.";
+
+Result<std::vector<std::string>> GetBootClassPath() {
+  const char* env_value = getenv("BOOTCLASSPATH");
+  if (env_value == nullptr || strlen(env_value) == 0) {
+    return Errorf("Failed to get environment variable 'BOOTCLASSPATH'");
+  }
+  return Split(env_value, ":");
+}
+
+Result<std::vector<std::string>> GetBootImageLocations(bool deny_art_apex_data_files) {
+  std::string error_msg;
+  std::string android_root = GetAndroidRootSafe(&error_msg);
+  if (!error_msg.empty()) {
+    return Errorf("Failed to get ANDROID_ROOT: {}", error_msg);
+  }
+
+  std::string location_str = GetDefaultBootImageLocation(android_root, deny_art_apex_data_files);
+  return Split(location_str, ":");
+}
+
+bool UseJitZygote() {
+  bool profile_boot_class_path_phenotype =
+      GetBoolProperty(std::string(kPhenotypeFlagPrefix) + "profilebootclasspath",
+                      /*default_value=*/false);
+
+  bool profile_boot_class_path =
+      GetBoolProperty(std::string(kDalvikVmFlagPrefix) + "profilebootclasspath",
+                      /*default_value=*/profile_boot_class_path_phenotype);
+
+  return profile_boot_class_path;
+}
+
+bool DenyArtApexDataFiles() {
+  return !GetBoolProperty("odsign.verification.success", /*default_value=*/false);
+}
+
 }  // namespace
 
 class Artd : public BnArtd {
@@ -60,11 +111,28 @@
                                       const std::string& in_instructionSet,
                                       const std::string& in_classLoaderContext,
                                       GetOptimizationStatusResult* _aidl_return) override {
-    (void)in_dexFile;
-    (void)in_instructionSet;
-    (void)in_classLoaderContext;
-    (void)_aidl_return;
-    return ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
+    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());
+    }
+
+    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> Start() {
@@ -80,6 +148,52 @@
 
     return {};
   }
+
+ private:
+  Result<OatFileAssistant::RuntimeOptions> GetRuntimeOptions() {
+    // We don't cache this system property because it can change.
+    bool use_jit_zygote = UseJitZygote();
+
+    if (!HasRuntimeOptionsCache()) {
+      OR_RETURN(BuildRuntimeOptionsCache());
+    }
+
+    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_,
+    };
+  }
+
+  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();
+
+    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));
+
+    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_;
 };
 
 }  // namespace artd
diff --git a/libartservice/service/java/com/android/server/art/ArtManagerLocal.java b/libartservice/service/java/com/android/server/art/ArtManagerLocal.java
index 19e529a..8d79b58 100644
--- a/libartservice/service/java/com/android/server/art/ArtManagerLocal.java
+++ b/libartservice/service/java/com/android/server/art/ArtManagerLocal.java
@@ -24,6 +24,7 @@
 import android.annotation.SystemApi;
 import android.os.Binder;
 import android.os.RemoteException;
+import android.os.ServiceManager;
 import android.util.Log;
 
 import com.android.internal.annotations.VisibleForTesting;
@@ -210,7 +211,6 @@
     @VisibleForTesting
     public static class Injector {
         private final PackageManagerLocal mPackageManagerLocal;
-        private final IArtd mArtd;
 
         Injector() {
             PackageManagerLocal packageManagerLocal = null;
@@ -225,9 +225,6 @@
                 Log.w(TAG, "Unable to get fake PackageManagerLocal", e);
             }
             mPackageManagerLocal = packageManagerLocal;
-
-            // TODO(jiakaiz): Use real artd.
-            mArtd = new LoggingArtd();
         }
 
         public PackageManagerLocal getPackageManagerLocal() {
@@ -235,7 +232,11 @@
         }
 
         public IArtd getArtd() {
-            return mArtd;
+            IArtd artd = IArtd.Stub.asInterface(ServiceManager.waitForService("artd"));
+            if (artd == null) {
+                throw new IllegalStateException("Unable to connect to artd");
+            }
+            return artd;
         }
     }
 }