Revert odrefresh split

This change is a manual revert of aosp/1843654, since there have been
lots of changes. odrefresh.cc and odrefresh_test.cc are the files that
conflict the most.

Bug: 211977683
Test: atest art_standalone_odrefresh_tests
Test: atest odsign_e2e_tests
Test: art/build/apex/runtests.sh
Test: lunch full-eng; m; art/build/apex/runtests.sh
Test: with master-art, art/tools/run-gtests.sh \
        /apex/com.android.art/bin/art/arm64/art_odrefresh_tests
Test: atest ComposHostTestCases

Change-Id: If279c4326ad4d4e5f4b7f5c7c0d995d522f795f5
diff --git a/artd/Android.bp b/artd/Android.bp
index 1a90c4c..6db1287 100644
--- a/artd/Android.bp
+++ b/artd/Android.bp
@@ -44,76 +44,6 @@
     ],
 }
 
-cc_defaults {
-    name: "libdexopt_defaults",
-    defaults: ["art_defaults"],
-    srcs: [
-        "libdexopt.cc",
-    ],
-    shared_libs: [
-        "artd-private-aidl-ndk",
-        "libbase",
-        "libbinder_ndk",
-        "liblog",
-    ],
-    export_include_dirs: [
-        "include/libdexopt",
-    ],
-    local_include_dirs: [
-        "include/libdexopt",
-    ],
-    visibility: [
-        "//art:__subpackages__",
-    ],
-}
-
-art_cc_library {
-    name: "libdexopt",
-    defaults: ["libdexopt_defaults"],
-    shared_libs: [
-        "libart",
-        "libartbase",
-    ],
-    apex_available: [
-        "com.android.art",
-        "com.android.art.debug",
-    ],
-}
-
-art_cc_library {
-    name: "libdexoptd",
-    defaults: ["libdexopt_defaults"],
-    shared_libs: [
-        "libartd",
-        "libartbased",
-    ],
-    apex_available: [
-        "com.android.art.debug",
-    ],
-}
-
-art_cc_defaults {
-    name: "art_artd_tests_defaults",
-    defaults: [
-        "libdexopt_defaults",
-    ],
-    srcs: [
-        "libdexopt_test.cc",
-    ],
-    static_libs: [
-        "libgmock",
-    ],
-}
-
-art_cc_test {
-    name: "art_standalone_artd_tests",
-    defaults: [
-        "art_standalone_gtest_defaults",
-        "art_artd_tests_defaults",
-    ],
-    test_config_template: "art_artd_tests.xml",
-}
-
 prebuilt_etc {
     name: "com.android.art.artd.init.rc",
     src: "artd.rc",
diff --git a/artd/art_artd_tests.xml b/artd/art_artd_tests.xml
deleted file mode 100644
index 7612cdd..0000000
--- a/artd/art_artd_tests.xml
+++ /dev/null
@@ -1,47 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2021 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.
--->
-<!-- Note: This test config file for {MODULE} is generated from a template. -->
-<configuration description="Runs {MODULE}.">
-    <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/>
-
-    <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
-        <option name="cleanup" value="true" />
-        <option name="push" value="{MODULE}->/data/local/tmp/{MODULE}/{MODULE}" />
-        <option name="append-bitness" value="true" />
-    </target_preparer>
-
-    <test class="com.android.tradefed.testtype.GTest" >
-        <option name="native-test-device-path" value="/data/local/tmp/{MODULE}" />
-        <option name="module-name" value="{MODULE}" />
-        <option name="ld-library-path-32" value="/apex/com.android.art/lib" />
-        <option name="ld-library-path-64" value="/apex/com.android.art/lib64" />
-
-        <option name="gtest-env" value="DEX2OATBOOTCLASSPATH=/apex/com.android.art/javalib/core-foo.jar:/system/framework/framework.jar" />
-        <option name="gtest-env" value="BOOTCLASSPATH=/apex/com.android.art/javalib/core-bar.jar:/system/framework/framework.jar:/apex/com.android.bar/javalib/bar.jar" />
-    </test>
-
-    <!-- When this test is run in a Mainline context (e.g. with `mts-tradefed`), only enable it if
-         one of the Mainline modules below is present on the device used for testing. -->
-    <object type="module_controller" class="com.android.tradefed.testtype.suite.module.MainlineTestModuleController">
-        <!-- ART Mainline Module (internal version). -->
-        <option name="mainline-module-package-name" value="com.google.android.art" />
-        <!-- ART Mainline Module (external (AOSP) version). -->
-        <option name="mainline-module-package-name" value="com.android.art" />
-    </object>
-
-    <!-- Only run tests if the device under test is SDK version 31 (Android 12) or above. -->
-    <object type="module_controller" class="com.android.tradefed.testtype.suite.module.Sdk31ModuleController" />
-</configuration>
diff --git a/artd/binder/Android.bp b/artd/binder/Android.bp
index 260340b..6acfe4e 100644
--- a/artd/binder/Android.bp
+++ b/artd/binder/Android.bp
@@ -51,27 +51,3 @@
         "//art:__subpackages__",
     ],
 }
-
-aidl_interface {
-    name: "artd-private-aidl",
-    srcs: [
-        "private/**/*.aidl",
-    ],
-    host_supported: true,
-    local_include_dir: "private",
-    backend: {
-        ndk: {
-            enabled: true,
-            apex_available: [
-                "com.android.art",
-                "com.android.art.debug",
-            ],
-            min_sdk_version: "31",
-        },
-    },
-    unstable: true,
-    visibility: [
-        "//system/tools/aidl/build",
-        "//art:__subpackages__",
-    ],
-}
diff --git a/artd/binder/private/com/android/art/CompilerFilter.aidl b/artd/binder/private/com/android/art/CompilerFilter.aidl
deleted file mode 100644
index 1e2902a..0000000
--- a/artd/binder/private/com/android/art/CompilerFilter.aidl
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright (C) 2021 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.
- */
-
-package com.android.art;
-
-@Backing(type="int")
-enum CompilerFilter {
-    UNSUPPORTED = 0,
-    VERIFY,
-    SPEED,
-    SPEED_PROFILE,
-}
-
diff --git a/artd/binder/private/com/android/art/DexoptBcpExtArgs.aidl b/artd/binder/private/com/android/art/DexoptBcpExtArgs.aidl
deleted file mode 100644
index 8253ead..0000000
--- a/artd/binder/private/com/android/art/DexoptBcpExtArgs.aidl
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright (C) 2021 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.
- */
-
-package com.android.art;
-
-import com.android.art.Isa;
-
-/**
- * Arguments for dexopt of BCP extension.
- *
- * <h1>Security Considerations:</h1>
- *
- * <p>On Android, both the data provider and consumer are currently assumed in the same trusting
- * domain * (e.g. since they are in the same process and the boundary is function call).
- *
- * <p>Compilation OS, on the contrary, plays role of data consumer and can't trust the data provided
- * by * the potentially malicious clients. The data must be validated before use.
- *
- * <p>When adding a new field, make sure the value space can be validated. See "SECURITY:" below for
- * examples.
- *
- * {@hide}
- */
-parcelable DexoptBcpExtArgs {
-    // SECURITY: File descriptor are currently integers. They are assumed trusted in Android right
-    // now. For CompOS, they are verified transparently to the compiler, thus can also be assumed
-    // trusted.
-    int[] dexFds;
-    // Note: It's more ideal to put bootClasspaths and bootClasspathFds in a Map<path, fd>, but Map
-    // is only supported by the Java backend of AIDL. As a result, we need to maintain both arrays
-    // manually.
-    String[] bootClasspaths;
-    int[] bootClasspathFds;
-    int[] profileFds;
-    int dirtyImageObjectsFd = -1;
-    // Output file descriptors
-    int oatFd = -1;
-    int vdexFd = -1;
-    int imageFd = -1;
-
-    // TODO(victorhsieh): Try to reconstruct behind the API, otherwise reasonable the security.
-    String[] dexPaths;
-    String oatLocation;
-
-    // SECURITY: The server may accept the request to produce code for the specified architecture,
-    // if supported.
-    Isa isa = Isa.UNSUPPORTED;
-
-    // SECURITY: Computational resource should not affect the compilation results.
-    int[] cpuSet;
-    int threads;
-}
diff --git a/artd/binder/private/com/android/art/DexoptSystemServerArgs.aidl b/artd/binder/private/com/android/art/DexoptSystemServerArgs.aidl
deleted file mode 100644
index 54aa867..0000000
--- a/artd/binder/private/com/android/art/DexoptSystemServerArgs.aidl
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Copyright (C) 2021 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.
- */
-
-package com.android.art;
-
-import com.android.art.CompilerFilter;
-import com.android.art.Isa;
-
-/**
- * Arguments for dexopt of a system server JAR.
- *
- * <h1>Security Considerations:</h1>
- *
- * <p>On Android, both the data provider and consumer are currently assumed in the same trusting
- * domain * (e.g. since they are in the same process and the boundary is function call).
- *
- * <p>Compilation OS, on the contrary, plays role of data consumer and can't trust the data provided
- * by * the potentially malicious clients. The data must be validated before use.
- *
- * <p>When adding a new field, make sure the value space can be validated. See "SECURITY:" below for
- * examples.
- *
- * {@hide}
- */
-parcelable DexoptSystemServerArgs {
-    // SECURITY: File descriptor are currently integers. They are assumed trusted in Android right
-    // now. For CompOS, they are verified transparently to the compiler, thus can also be assumed
-    // trusted.
-    int dexFd = -1;
-    int profileFd = -1;
-    // Note: It's more ideal to put bootClasspaths and bootClasspathFds in a Map<path, fd>
-    // (similarly to the other bootClasspath*Fds), but Map is only supported by the Java backend of
-    // AIDL. As a result, we need to maintain both arrays manually. Note that this array is not used
-    // as -Xbootclasspath but as a container of the mapping keys for the arrays below.
-    String[] bootClasspaths;
-    int[] bootClasspathFds;
-    int[] bootClasspathImageFds;
-    int[] bootClasspathVdexFds;
-    int[] bootClasspathOatFds;
-    int[] classloaderFds;
-    // Output file descriptors
-    int imageFd = -1;
-    int vdexFd = -1;
-    int oatFd = -1;
-
-    // TODO(victorhsieh): Try to reconstruct behind the API, otherwise reasonable the security.
-    String dexPath;
-    String oatLocation;
-    String[] classloaderContext;
-    String bootImage;
-    boolean classloaderContextAsParent;
-
-    // SECURITY: The server may accept the request to produce code for the specified architecture,
-    // if supported.
-    Isa isa = Isa.UNSUPPORTED;
-
-    // SECURITY: The server may apply compiler filter as long as the compilation can be truthful.
-    // For example, given that the profile is valid, the produced code should still be translated
-    // correctly. Effectively, what a malicious attacker can do is to produce less/more efficient
-    // code.
-    CompilerFilter compilerFilter = CompilerFilter.UNSUPPORTED;
-
-    // SECURITY: Computational resource should not affect the compilation results.
-    int[] cpuSet;
-    int threads;
-}
diff --git a/artd/binder/private/com/android/art/Isa.aidl b/artd/binder/private/com/android/art/Isa.aidl
deleted file mode 100644
index 3a2bd36..0000000
--- a/artd/binder/private/com/android/art/Isa.aidl
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright (C) 2021 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.
- */
-
-package com.android.art;
-
-@Backing(type="int")
-enum Isa {
-    UNSUPPORTED = 0,
-    ARM,
-    ARM64,
-    THUMB2,
-    X86,
-    X86_64,
-}
diff --git a/artd/include/libdexopt/libdexopt.h b/artd/include/libdexopt/libdexopt.h
deleted file mode 100644
index 2e958be..0000000
--- a/artd/include/libdexopt/libdexopt.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2021 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_INCLUDE_LIBDEXOPT_LIBDEXOPT_H_
-#define ART_ARTD_INCLUDE_LIBDEXOPT_LIBDEXOPT_H_
-
-#include <string>
-#include <vector>
-
-#include "android-base/result.h"
-
-#include "aidl/com/android/art/DexoptBcpExtArgs.h"
-#include "aidl/com/android/art/DexoptSystemServerArgs.h"
-
-namespace art {
-
-android::base::Result<void> AddDex2oatArgsFromBcpExtensionArgs(
-    const aidl::com::android::art::DexoptBcpExtArgs& dexopt_args,
-    std::vector<std::string>& dex2oat_args);
-
-android::base::Result<void> AddDex2oatArgsFromSystemServerArgs(
-    const aidl::com::android::art::DexoptSystemServerArgs& dexopt_args,
-    std::vector<std::string>& dex2oat_args);
-
-}  // namespace art
-
-#endif  // ART_ARTD_INCLUDE_LIBDEXOPT_LIBDEXOPT_H_
diff --git a/artd/libdexopt.cc b/artd/libdexopt.cc
deleted file mode 100644
index b6982c1..0000000
--- a/artd/libdexopt.cc
+++ /dev/null
@@ -1,327 +0,0 @@
-/*
- * Copyright (C) 2021 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 "libdexopt.h"
-#define LOG_TAG "libdexopt"
-
-#include <map>
-#include <string>
-#include <vector>
-
-#include "android-base/stringprintf.h"
-#include "android-base/strings.h"
-#include "android-base/result.h"
-#include "base/file_utils.h"
-#include "log/log.h"
-
-#include "aidl/com/android/art/CompilerFilter.h"
-#include "aidl/com/android/art/DexoptBcpExtArgs.h"
-#include "aidl/com/android/art/DexoptSystemServerArgs.h"
-#include "aidl/com/android/art/Isa.h"
-
-namespace art {
-
-namespace {
-
-using aidl::com::android::art::CompilerFilter;
-using aidl::com::android::art::DexoptBcpExtArgs;
-using aidl::com::android::art::DexoptSystemServerArgs;
-using aidl::com::android::art::Isa;
-using android::base::Error;
-using android::base::Result;
-
-std::string GetEnvironmentVariableOrDie(const char* name) {
-  const char* value = getenv(name);
-  LOG_ALWAYS_FATAL_IF(value == nullptr, "%s is not defined.", name);
-  return value;
-}
-
-std::string GetDex2oatBootClasspath() {
-  return GetEnvironmentVariableOrDie("DEX2OATBOOTCLASSPATH");
-}
-
-std::string GetBootClasspath() {
-  return GetEnvironmentVariableOrDie("BOOTCLASSPATH");
-}
-
-std::string ToInstructionSetString(Isa isa) {
-  switch (isa) {
-    case Isa::ARM:
-    case Isa::THUMB2:
-      return "arm";
-    case Isa::ARM64:
-      return "arm64";
-    case Isa::X86:
-      return "x86";
-    case Isa::X86_64:
-      return "x86_64";
-    default:
-      UNREACHABLE();
-  }
-}
-
-const char* CompilerFilterAidlToString(CompilerFilter compiler_filter) {
-  switch (compiler_filter) {
-    case CompilerFilter::SPEED_PROFILE:
-      return "speed-profile";
-    case CompilerFilter::SPEED:
-      return"speed";
-    case CompilerFilter::VERIFY:
-      return "verify";
-    default:
-      UNREACHABLE();
-  }
-}
-
-Result<void> AddBootClasspath(/*inout*/ std::vector<std::string>& cmdline,
-                              const std::string& bootclasspath_env,
-                              const std::vector<std::string>& boot_classpaths,
-                              const std::vector<int>& boot_classpath_fds) {
-  if (boot_classpaths.empty()) {
-    return Errorf("Missing BCP files");
-  }
-
-  if (boot_classpaths.size() != boot_classpath_fds.size()) {
-    return Errorf("Number of BCP paths (%d) != number of FDs (%d)", boot_classpaths.size(),
-                  boot_classpath_fds.size());
-  }
-
-  cmdline.emplace_back("--runtime-arg");
-  cmdline.emplace_back("-Xbootclasspath:" + bootclasspath_env);
-
-  // Construct a path->fd map from both arrays. If the client provides duplicated paths, only one
-  // will be used. This is fine since the client may not be trusted any way.
-  std::map<std::string, int> bcp_map;
-  auto zip = [](const std::string &path, int fd) { return std::make_pair(path, fd); };
-  std::transform(boot_classpaths.begin(), boot_classpaths.end(), boot_classpath_fds.begin(),
-                 std::inserter(bcp_map, bcp_map.end()), zip);
-
-  std::vector<std::string> jar_paths = android::base::Split(bootclasspath_env, ":");
-  std::stringstream ss;
-  ss << "-Xbootclasspathfds";
-  for (auto& jar_path : jar_paths) {
-    auto iter = bcp_map.find(jar_path);
-    if (iter == bcp_map.end()) {
-      ss << ":-1";
-    } else {
-      ss << ":" << std::to_string(iter->second);
-      bcp_map.erase(iter);
-    }
-  }
-  cmdline.emplace_back("--runtime-arg");
-  cmdline.emplace_back(ss.str());
-
-  if (!bcp_map.empty()) {
-    std::stringstream error_ss;
-    for (const auto &[key, _] : bcp_map) {
-      error_ss << key << ":";
-    }
-    return Error() << "Residual BCP paths: " << error_ss.str();
-  }
-  return {};
-}
-
-Result<void> AddCompiledBootClasspathFdsIfAny(/*inout*/ std::vector<std::string>& cmdline,
-                                              const DexoptSystemServerArgs& args) {
-  // Result
-  if ((args.bootClasspathImageFds.size() != args.bootClasspathOatFds.size()) ||
-      (args.bootClasspathImageFds.size() != args.bootClasspathVdexFds.size()) ||
-      (args.bootClasspathImageFds.size() != args.bootClasspaths.size())) {
-    return Errorf("Inconsistent FD numbers of BCP artifacts: jar/image/vdex/oat: %d/%d/%d/%d",
-                  args.bootClasspaths.size(), args.bootClasspathImageFds.size(),
-                  args.bootClasspathVdexFds.size(), args.bootClasspathOatFds.size());
-  }
-
-  if (!args.bootClasspathImageFds.empty()) {
-    cmdline.emplace_back("--runtime-arg");
-    cmdline.emplace_back(
-        "-Xbootclasspathimagefds:" + android::base::Join(args.bootClasspathImageFds, ':'));
-    cmdline.emplace_back("--runtime-arg");
-    cmdline.emplace_back(
-        "-Xbootclasspathoatfds:" + android::base::Join(args.bootClasspathOatFds, ':'));
-    cmdline.emplace_back("--runtime-arg");
-    cmdline.emplace_back(
-        "-Xbootclasspathvdexfds:" + android::base::Join(args.bootClasspathVdexFds, ':'));
-  }
-  return {};
-}
-
-void AddDex2OatConcurrencyArguments(/*inout*/ std::vector<std::string>& cmdline,
-                                    int threads,
-                                    const std::vector<int>& cpu_set) {
-  if (threads > 0) {
-      cmdline.emplace_back(android::base::StringPrintf("-j%d", threads));
-  }
-  if (!cpu_set.empty()) {
-      cmdline.emplace_back("--cpu-set=" + android::base::Join(cpu_set, ','));
-  }
-}
-
-void AddDex2OatCommonOptions(/*inout*/ std::vector<std::string>& cmdline) {
-  cmdline.emplace_back("--android-root=out/empty");
-  cmdline.emplace_back("--abort-on-hard-verifier-error");
-  cmdline.emplace_back("--no-abort-on-soft-verifier-error");
-  cmdline.emplace_back("--compilation-reason=boot");
-  cmdline.emplace_back("--image-format=lz4");
-  cmdline.emplace_back("--force-determinism");
-  cmdline.emplace_back("--resolve-startup-const-strings=true");
-
-  // Avoid storing dex2oat cmdline in oat header. We want to be sure that the compiled artifacts
-  // are identical regardless of where the compilation happened. But some of the cmdline flags tends
-  // to be unstable, e.g. those contains FD numbers. To avoid the problem, the whole cmdline is not
-  // added to the oat header.
-  cmdline.emplace_back("--avoid-storing-invocation");
-}
-
-void AddDex2OatDebugInfo(/*inout*/ std::vector<std::string>& cmdline) {
-  cmdline.emplace_back("--generate-mini-debug-info");
-  cmdline.emplace_back("--strip");
-}
-
-}  // namespace
-
-Result<void> AddDex2oatArgsFromBcpExtensionArgs(const DexoptBcpExtArgs& args,
-                                                /*out*/ std::vector<std::string>& cmdline) {
-  // Common dex2oat flags
-  AddDex2OatCommonOptions(cmdline);
-  AddDex2OatDebugInfo(cmdline);
-
-  cmdline.emplace_back("--instruction-set=" + ToInstructionSetString(args.isa));
-
-  if (!args.profileFds.empty()) {
-    for (int fd : args.profileFds) {
-      cmdline.emplace_back(android::base::StringPrintf("--profile-file-fd=%d", fd));
-    }
-    cmdline.emplace_back("--compiler-filter=speed-profile");
-  } else {
-    cmdline.emplace_back("--compiler-filter=speed");
-  }
-
-  // Compile as a single image for fewer files and slightly less memory overhead.
-  cmdline.emplace_back("--single-image");
-
-  cmdline.emplace_back(android::base::StringPrintf("--base=0x%08x", ART_BASE_ADDRESS));
-
-  if (args.dirtyImageObjectsFd >= 0) {
-    cmdline.emplace_back(android::base::StringPrintf("--dirty-image-objects-fd=%d",
-                                                     args.dirtyImageObjectsFd));
-  }
-
-  if (args.dexPaths.size() != args.dexFds.size()) {
-    return Errorf("Mismatched number of dexPaths (%d) and dexFds (%d)",
-                  args.dexPaths.size(),
-                  args.dexFds.size());
-  }
-  for (unsigned int i = 0; i < args.dexPaths.size(); ++i) {
-    cmdline.emplace_back("--dex-file=" + args.dexPaths[i]);
-    cmdline.emplace_back(android::base::StringPrintf("--dex-fd=%d", args.dexFds[i]));
-  }
-
-  std::string bcp_env = GetDex2oatBootClasspath();
-  auto result = AddBootClasspath(cmdline, bcp_env, args.bootClasspaths, args.bootClasspathFds);
-  if (!result.ok()) {
-    return result.error();
-  }
-
-  cmdline.emplace_back("--oat-location=" + args.oatLocation);
-
-  // Output files
-  if (args.imageFd < 0) {
-    return Error() << "imageFd is missing";
-  }
-  cmdline.emplace_back(android::base::StringPrintf("--image-fd=%d", args.imageFd));
-  if (args.vdexFd < 0) {
-    return Error() << "vdexFd is missing";
-  }
-  cmdline.emplace_back(android::base::StringPrintf("--output-vdex-fd=%d", args.vdexFd));
-  if (args.oatFd < 0) {
-    return Error() << "oatFd is missing";
-  }
-  cmdline.emplace_back(android::base::StringPrintf("--oat-fd=%d", args.oatFd));
-
-  AddDex2OatConcurrencyArguments(cmdline, args.threads, args.cpuSet);
-
-  return {};
-}
-
-Result<void> AddDex2oatArgsFromSystemServerArgs(const DexoptSystemServerArgs& args,
-                                                /*out*/ std::vector<std::string>& cmdline) {
-  cmdline.emplace_back("--dex-file=" + args.dexPath);
-  cmdline.emplace_back(android::base::StringPrintf("--dex-fd=%d", args.dexFd));
-
-  // Common dex2oat flags
-  AddDex2OatCommonOptions(cmdline);
-  AddDex2OatDebugInfo(cmdline);
-
-  cmdline.emplace_back("--instruction-set=" + ToInstructionSetString(args.isa));
-
-  if (args.compilerFilter == CompilerFilter::SPEED_PROFILE) {
-    if (args.profileFd < 0) {
-      return Error() << "profileFd is missing";
-    }
-    cmdline.emplace_back(android::base::StringPrintf("--profile-file-fd=%d", args.profileFd));
-    cmdline.emplace_back("--compiler-filter=speed-profile");
-  } else {
-    cmdline.emplace_back("--compiler-filter=" +
-                         std::string(CompilerFilterAidlToString(args.compilerFilter)));
-  }
-
-  // Output files
-  if (args.imageFd < 0) {
-    return Error() << "imageFd is missing";
-  }
-  cmdline.emplace_back(android::base::StringPrintf("--app-image-fd=%d", args.imageFd));
-  if (args.vdexFd < 0) {
-    return Error() << "vdexFd is missing";
-  }
-  cmdline.emplace_back(android::base::StringPrintf("--output-vdex-fd=%d", args.vdexFd));
-  if (args.oatFd < 0) {
-    return Error() << "oatFd is missing";
-  }
-  cmdline.emplace_back(android::base::StringPrintf("--oat-fd=%d", args.oatFd));
-  cmdline.emplace_back("--oat-location=" + args.oatLocation);
-
-  std::string bcp_env = GetBootClasspath();
-  auto result = AddBootClasspath(cmdline, bcp_env, args.bootClasspaths, args.bootClasspathFds);
-  if (!result.ok()) {
-    return result.error();
-  }
-  result = AddCompiledBootClasspathFdsIfAny(cmdline, args);
-  if (!result.ok()) {
-    return result.error();
-  }
-
-  if (args.classloaderFds.empty()) {
-    cmdline.emplace_back("--class-loader-context=PCL[]");
-  } else {
-    const std::string context_path = android::base::Join(args.classloaderContext, ':');
-    if (args.classloaderContextAsParent) {
-      cmdline.emplace_back("--class-loader-context=PCL[];PCL[" + context_path + "]");
-    } else {
-      cmdline.emplace_back("--class-loader-context=PCL[" + context_path + "]");
-    }
-    cmdline.emplace_back("--class-loader-context-fds=" +
-                         android::base::Join(args.classloaderFds, ':'));
-  }
-
-  cmdline.emplace_back("--boot-image=" + args.bootImage);
-
-  AddDex2OatConcurrencyArguments(cmdline, args.threads, args.cpuSet);
-
-  return {};
-}
-
-}  // namespace art
diff --git a/artd/libdexopt_test.cc b/artd/libdexopt_test.cc
deleted file mode 100644
index 3cc340b..0000000
--- a/artd/libdexopt_test.cc
+++ /dev/null
@@ -1,341 +0,0 @@
-/*
- * Copyright (C) 2021 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 "libdexopt.h"
-
-#include <string>
-#include <vector>
-
-#include "android-base/result.h"
-#include "android-base/strings.h"
-#include "base/common_art_test.h"
-#include "gmock/gmock.h"
-#include "gtest/gtest.h"
-
-#include "aidl/com/android/art/CompilerFilter.h"
-#include "aidl/com/android/art/DexoptBcpExtArgs.h"
-#include "aidl/com/android/art/DexoptSystemServerArgs.h"
-#include "aidl/com/android/art/Isa.h"
-
-namespace art {
-
-using ::testing::AllOf;
-using ::testing::Contains;
-using ::testing::HasSubstr;
-using ::testing::Not;
-using aidl::com::android::art::CompilerFilter;
-using aidl::com::android::art::DexoptBcpExtArgs;
-using aidl::com::android::art::DexoptSystemServerArgs;
-using aidl::com::android::art::Isa;
-using android::base::Result;
-
-std::string GetEnvironmentVariableOrDie(const char* name) {
-  const char* value = getenv(name);
-  EXPECT_NE(value, nullptr);
-  return value;
-}
-
-// See art_artd_tests.xml for *CLASSPATH setup.
-class LibDexoptTest : public CommonArtTest {
- protected:
-  void SetUp() override {
-    CommonArtTest::SetUp();
-
-    default_bcp_ext_args_.dexFds = {10, 11};
-    default_bcp_ext_args_.bootClasspaths = android::base::Split(
-        GetEnvironmentVariableOrDie("DEX2OATBOOTCLASSPATH"), ":");  // from art_artd_tests.xml
-    default_bcp_ext_args_.bootClasspathFds = {21, 22};
-    default_bcp_ext_args_.profileFds = {30, 31};
-    default_bcp_ext_args_.dirtyImageObjectsFd = 31;
-    default_bcp_ext_args_.imageFd = 90;
-    default_bcp_ext_args_.vdexFd = 91;
-    default_bcp_ext_args_.oatFd = 92;
-    default_bcp_ext_args_.dexPaths = {"/path/to/foo.jar", "/path/to/bar.jar"};
-    default_bcp_ext_args_.oatLocation = "/oat/location/bar.odex";
-    default_bcp_ext_args_.isa = Isa::X86_64;
-    default_bcp_ext_args_.cpuSet = {0, 1};
-    default_bcp_ext_args_.threads = 42;
-    ASSERT_EQ(default_bcp_ext_args_.bootClasspaths.size(),
-              default_bcp_ext_args_.bootClasspathFds.size());
-
-    default_system_server_args_.dexFd = 10;
-    default_system_server_args_.profileFd = 11;
-    default_system_server_args_.bootClasspaths = android::base::Split(
-        GetEnvironmentVariableOrDie("BOOTCLASSPATH"), ":");  // from art_artd_tests.xml
-    default_system_server_args_.bootClasspathFds = {21, 22, 23};
-    default_system_server_args_.bootClasspathImageFds = {-1, 31, -1};
-    default_system_server_args_.bootClasspathVdexFds = {-1, 32, -1};
-    default_system_server_args_.bootClasspathOatFds = {-1, 33, -1};
-    default_system_server_args_.classloaderFds = {40, 41};
-    default_system_server_args_.classloaderContext = {"/cl/abc.jar", "/cl/def.jar"};
-    default_system_server_args_.imageFd = 90;
-    default_system_server_args_.vdexFd = 91;
-    default_system_server_args_.oatFd = 92;
-    default_system_server_args_.dexPath = "/path/to/foo.jar";
-    default_system_server_args_.oatLocation = "/oat/location/bar.odex";
-    default_system_server_args_.isa = Isa::X86_64;
-    default_system_server_args_.compilerFilter = CompilerFilter::SPEED_PROFILE;
-    default_system_server_args_.cpuSet = {0, 1};
-    default_system_server_args_.threads = 42;
-    default_system_server_args_.bootImage = "/path/to/boot.art";
-    ASSERT_EQ(default_system_server_args_.bootClasspaths.size(),
-              default_system_server_args_.bootClasspathFds.size());
-  }
-
-  void TearDown() override {
-    CommonArtTest::TearDown();
-  }
-
-  std::vector<std::string> Dex2oatArgsFromBcpExtensionArgs(const DexoptBcpExtArgs& args) {
-    std::vector<std::string> cmdline;
-    Result<void> result = AddDex2oatArgsFromBcpExtensionArgs(args, cmdline);
-    EXPECT_TRUE(result.ok()) << "Failed expectation: " << result.error().message();
-    return cmdline;
-  }
-
-  std::vector<std::string> Dex2oatArgsFromSystemServerArgs(const DexoptSystemServerArgs& args) {
-    std::vector<std::string> cmdline;
-    Result<void> result = AddDex2oatArgsFromSystemServerArgs(args, cmdline);
-    EXPECT_TRUE(result.ok()) << "Failed expectation: " << result.error().message();
-    return cmdline;
-  }
-
-  bool DexoptBcpExtArgsIsInvalid(const DexoptBcpExtArgs& args) {
-    std::vector<std::string> cmdline;
-    Result<void> result = AddDex2oatArgsFromBcpExtensionArgs(args, cmdline);
-    return result.ok();
-  }
-
-  bool DexoptSystemServerArgsIsInvalid(const DexoptSystemServerArgs& args) {
-    std::vector<std::string> cmdline;
-    Result<void> result = AddDex2oatArgsFromSystemServerArgs(args, cmdline);
-    return result.ok();
-  }
-
-  DexoptBcpExtArgs default_bcp_ext_args_;
-  DexoptSystemServerArgs default_system_server_args_;
-};
-
-TEST_F(LibDexoptTest, AddDex2oatArgsFromBcpExtensionArgs) {
-  // Test basics with default args
-  {
-    std::vector<std::string> cmdline = Dex2oatArgsFromBcpExtensionArgs(default_bcp_ext_args_);
-
-    EXPECT_THAT(cmdline,
-                AllOf(Contains("--dex-fd=10"),
-                      Contains("--dex-fd=11"),
-                      Contains("--dex-file=/path/to/foo.jar"),
-                      Contains("--dex-file=/path/to/bar.jar"),
-                      Contains(HasSubstr("-Xbootclasspath:")),
-                      Contains("-Xbootclasspathfds:21:22"),
-
-                      Contains("--profile-file-fd=30"),
-                      Contains("--profile-file-fd=31"),
-                      Contains("--compiler-filter=speed-profile"),
-
-                      Contains("--image-fd=90"),
-                      Contains("--output-vdex-fd=91"),
-                      Contains("--oat-fd=92"),
-                      Contains("--oat-location=/oat/location/bar.odex"),
-
-                      Contains("--dirty-image-objects-fd=31"),
-                      Contains("--instruction-set=x86_64"),
-                      Contains("--cpu-set=0,1"),
-                      Contains("-j42"),
-
-                      Contains(HasSubstr("--base="))));
-  }
-
-  // No profile
-  {
-    auto args = default_bcp_ext_args_;
-    args.profileFds = {};
-    std::vector<std::string> cmdline = Dex2oatArgsFromBcpExtensionArgs(args);
-
-    EXPECT_THAT(cmdline, AllOf(
-        Not(Contains(HasSubstr("--profile-file-fd="))),
-        Contains("--compiler-filter=speed")));
-  }
-
-  // No dirty image objects fd
-  {
-    auto args = default_bcp_ext_args_;
-    args.dirtyImageObjectsFd = -1;
-    std::vector<std::string> cmdline = Dex2oatArgsFromBcpExtensionArgs(args);
-
-    EXPECT_THAT(cmdline, Not(Contains(HasSubstr("--dirty-image-objects-fd"))));
-  }
-}
-
-TEST_F(LibDexoptTest, AddDex2oatArgsFromBcpExtensionArgs_InvalidArguments) {
-  // Mismatched dex number
-  {
-    auto args = default_bcp_ext_args_;
-    args.dexPaths = {"/path/to/foo.jar", "/path/to/bar.jar"};
-    args.dexFds = {100, 101, 102};
-
-    EXPECT_FALSE(DexoptBcpExtArgsIsInvalid(args));
-  }
-
-  // Mismatched classpath arguments
-  {
-    auto args = default_bcp_ext_args_;
-    args.bootClasspathFds.emplace_back(200);
-
-    EXPECT_FALSE(DexoptBcpExtArgsIsInvalid(args));
-  }
-
-  // Mismatched classpath arguments
-  {
-    auto args = default_bcp_ext_args_;
-    args.bootClasspaths.emplace_back("/unrecognized/jar");
-
-    EXPECT_FALSE(DexoptBcpExtArgsIsInvalid(args));
-  }
-
-  // Missing output fds
-  {
-    auto args = default_bcp_ext_args_;
-    args.imageFd = -1;
-    EXPECT_FALSE(DexoptBcpExtArgsIsInvalid(args));
-
-    args = default_bcp_ext_args_;
-    args.vdexFd = -1;
-    EXPECT_FALSE(DexoptBcpExtArgsIsInvalid(args));
-
-    args = default_bcp_ext_args_;
-    args.oatFd = -1;
-    EXPECT_FALSE(DexoptBcpExtArgsIsInvalid(args));
-  }
-}
-
-TEST_F(LibDexoptTest, AddDex2oatArgsFromSystemServerArgs) {
-  // Test basics with default args
-  {
-    std::vector<std::string> cmdline = Dex2oatArgsFromSystemServerArgs(default_system_server_args_);
-
-    EXPECT_THAT(cmdline,
-                AllOf(Contains("--dex-fd=10"),
-                      Contains("--dex-file=/path/to/foo.jar"),
-                      Contains(HasSubstr("-Xbootclasspath:")),
-                      Contains("-Xbootclasspathfds:21:22:23"),
-                      Contains("-Xbootclasspathimagefds:-1:31:-1"),
-                      Contains("-Xbootclasspathvdexfds:-1:32:-1"),
-                      Contains("-Xbootclasspathoatfds:-1:33:-1"),
-
-                      Contains("--profile-file-fd=11"),
-                      Contains("--compiler-filter=speed-profile"),
-
-                      Contains("--app-image-fd=90"),
-                      Contains("--output-vdex-fd=91"),
-                      Contains("--oat-fd=92"),
-                      Contains("--oat-location=/oat/location/bar.odex"),
-
-                      Contains("--class-loader-context-fds=40:41"),
-                      Contains("--class-loader-context=PCL[/cl/abc.jar:/cl/def.jar]"),
-
-                      Contains("--instruction-set=x86_64"),
-                      Contains("--cpu-set=0,1"),
-                      Contains("-j42"),
-
-                      Contains("--boot-image=/path/to/boot.art")));
-  }
-
-  // Test different compiler filters
-  {
-    // speed
-    auto args = default_system_server_args_;
-    args.compilerFilter = CompilerFilter::SPEED;
-    std::vector<std::string> cmdline = Dex2oatArgsFromSystemServerArgs(args);
-
-    EXPECT_THAT(cmdline, AllOf(
-        Not(Contains(HasSubstr("--profile-file-fd="))),
-        Contains("--compiler-filter=speed")));
-
-    // verify
-    args = default_system_server_args_;
-    args.compilerFilter = CompilerFilter::VERIFY;
-    cmdline = Dex2oatArgsFromSystemServerArgs(args);
-
-    EXPECT_THAT(cmdline, AllOf(
-        Not(Contains(HasSubstr("--profile-file-fd="))),
-        Contains("--compiler-filter=verify")));
-  }
-
-  // Test empty classloader context
-  {
-    auto args = default_system_server_args_;
-    args.classloaderFds = {};
-    args.classloaderContext = {};
-    std::vector<std::string> cmdline = Dex2oatArgsFromSystemServerArgs(args);
-
-    EXPECT_THAT(cmdline, AllOf(
-        Not(Contains(HasSubstr("--class-loader-context-fds"))),
-        Contains("--class-loader-context=PCL[]")));
-  }
-
-  // Test classloader context as parent
-  {
-    auto args = default_system_server_args_;
-    args.classloaderContextAsParent = true;
-    std::vector<std::string> cmdline = Dex2oatArgsFromSystemServerArgs(args);
-
-    EXPECT_THAT(cmdline, Contains("--class-loader-context=PCL[];PCL[/cl/abc.jar:/cl/def.jar]"));
-  }
-}
-
-TEST_F(LibDexoptTest, AddDex2oatArgsFromSystemServerArgs_InvalidArguments) {
-  // Mismatched classpath arguments
-  {
-    auto args = default_system_server_args_;
-    args.bootClasspathFds.emplace_back(200);
-
-    EXPECT_FALSE(DexoptSystemServerArgsIsInvalid(args));
-  }
-
-  // Unrecognized jar path
-  {
-    auto args = default_system_server_args_;
-    args.bootClasspaths.emplace_back("/unrecognized/jar");
-
-    EXPECT_FALSE(DexoptSystemServerArgsIsInvalid(args));
-  }
-
-  // speed-profile without profile fd
-  {
-    auto args = default_system_server_args_;
-    args.compilerFilter = CompilerFilter::SPEED_PROFILE;
-    args.profileFd = -1;
-    EXPECT_FALSE(DexoptSystemServerArgsIsInvalid(args));
-  }
-
-  // Missing output fds
-  {
-    auto args = default_system_server_args_;
-    args.imageFd = -1;
-    EXPECT_FALSE(DexoptSystemServerArgsIsInvalid(args));
-
-    args = default_system_server_args_;
-    args.vdexFd = -1;
-    EXPECT_FALSE(DexoptSystemServerArgsIsInvalid(args));
-
-    args = default_system_server_args_;
-    args.oatFd = -1;
-    EXPECT_FALSE(DexoptSystemServerArgsIsInvalid(args));
-  }
-}
-
-}  // namespace art
diff --git a/build/apex/Android.bp b/build/apex/Android.bp
index d299c72..015c84d 100644
--- a/build/apex/Android.bp
+++ b/build/apex/Android.bp
@@ -306,7 +306,7 @@
     defaults: ["com.android.art-device-defaults-minus-odrefresh"],
     multilib: {
         first: {
-           binaries: ["odrefresh"],
+            binaries: ["odrefresh"],
         },
     },
 }
@@ -368,7 +368,7 @@
     defaults: ["com.android.art-device-defaults-minus-odrefresh"],
     multilib: {
         first: {
-           binaries: ["odrefresh_broken"],
+            binaries: ["odrefresh_broken"],
         },
     },
     key: "com.android.art.key",
@@ -417,16 +417,12 @@
     "art_libdexfile_support_tests",
     "art_libprofile_tests",
     "art_oatdump_tests",
+    "art_odrefresh_tests",
     "art_profman_tests",
     "art_runtime_compiler_tests",
     "art_runtime_tests",
     "art_sigchain_tests",
 ]
-art_gtests_first_only = [
-    // We only ship "first" for odrefresh, so don't bother test the "second". This also avoids a
-    // problem where some dependencies may only build "first" and doesn't have "second".
-    "art_odrefresh_tests",
-]
 
 // "Testing" version of the ART APEX module (containing both release
 // and debug variants, additional tools, and ART gtests), for testing
@@ -436,14 +432,7 @@
     defaults: ["com.android.art-devel-defaults"],
     file_contexts: ":com.android.art.debug-file_contexts",
     certificate: ":com.android.art.certificate",
-    multilib: {
-        both: {
-            tests: art_gtests,
-        },
-        first: {
-            tests: art_gtests_first_only,
-        },
-    },
+    tests: art_gtests,
     binaries: ["signal_dumper"], // Need signal_dumper for run-tests.
     updatable: false,
 }
diff --git a/build/apex/art_apex_test.py b/build/apex/art_apex_test.py
index 17eb18e..970fff0 100755
--- a/build/apex/art_apex_test.py
+++ b/build/apex/art_apex_test.py
@@ -552,8 +552,6 @@
     # Check internal libraries for ART.
     self._checker.check_native_library('libperfetto_hprof')
     self._checker.check_prefer64_library('artd-aidl-ndk')
-    self._checker.check_prefer64_library('artd-private-aidl-ndk')
-    self._checker.check_prefer64_library('libdexopt')
 
     # Check internal Java libraries
     self._checker.check_java_library("service-art")
@@ -684,15 +682,13 @@
     self._checker.check_art_test_executable('art_libdexfile_tests')
     self._checker.check_art_test_executable('art_libprofile_tests')
     self._checker.check_art_test_executable('art_oatdump_tests')
-    self._checker.check_art_test_executable('art_odrefresh_tests',
-                                            multilib=MULTILIB_FIRST)
+    self._checker.check_art_test_executable('art_odrefresh_tests')
     self._checker.check_art_test_executable('art_profman_tests')
     self._checker.check_art_test_executable('art_runtime_compiler_tests')
     self._checker.check_art_test_executable('art_runtime_tests')
     self._checker.check_art_test_executable('art_sigchain_tests')
 
     # Check ART test (internal) libraries.
-    self._checker.check_prefer64_library('libdexoptd')
     self._checker.check_native_library('libartd-gtest')
     self._checker.check_native_library('libartd-simulator-container')
 
diff --git a/odrefresh/Android.bp b/odrefresh/Android.bp
index 4ed395d..04d65b9 100644
--- a/odrefresh/Android.bp
+++ b/odrefresh/Android.bp
@@ -29,7 +29,6 @@
         "odrefresh.cc",
         "odr_common.cc",
         "odr_compilation_log.cc",
-        "odr_dexopt.cc",
         "odr_fs_utils.cc",
         "odr_metrics.cc",
         "odr_metrics_record.cc",
@@ -42,7 +41,6 @@
         "art-odrefresh-operator-srcs",
     ],
     shared_libs: [
-        "artd-private-aidl-ndk",
         "libartpalette",
         "libbase",
         "liblog",
@@ -110,7 +108,6 @@
     shared_libs: [
         "libart",
         "libartbase",
-        "libdexopt",
     ],
     apex_available: [
         "com.android.art",
@@ -142,7 +139,6 @@
     shared_libs: [
         "libartd",
         "libartbased",
-        "libdexoptd",
     ],
     apex_available: [
         "com.android.art.debug",
@@ -208,7 +204,6 @@
     host_supported: false,
     shared_libs: [
         "libdexfiled",
-        "libdexoptd",
     ],
     // The test config template is needed even though it's not used by the test
     // runner. Otherwise, Soong will generate a test config, which is adding
@@ -227,7 +222,6 @@
     ],
     shared_libs: [
         "libdexfile",
-        "libdexopt",
     ],
 }
 
diff --git a/odrefresh/odr_dexopt.cc b/odrefresh/odr_dexopt.cc
deleted file mode 100644
index 34e10c2..0000000
--- a/odrefresh/odr_dexopt.cc
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Copyright (C) 2021 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 "odr_dexopt.h"
-
-#include <vector>
-
-#include "android-base/logging.h"
-#include "android-base/strings.h"
-#include "exec_utils.h"
-#include "log/log.h"
-#include "odr_config.h"
-#include "libdexopt.h"
-
-#include "aidl/com/android/art/DexoptBcpExtArgs.h"
-#include "aidl/com/android/art/DexoptSystemServerArgs.h"
-
-namespace art {
-namespace odrefresh {
-
-using aidl::com::android::art::DexoptBcpExtArgs;
-using aidl::com::android::art::DexoptSystemServerArgs;
-
-namespace {
-
-int ExecAndReturnCode(ExecUtils* exec_utils,
-                      std::vector<std::string>& cmdline,
-                      time_t timeout_secs,
-                      /*out*/ bool* timed_out,
-                      /*out*/ std::string* error_msg) {
-  LOG(DEBUG) << "odr_dexopt cmdline: " << android::base::Join(cmdline, ' ') << " [timeout "
-             << timeout_secs << "s]";
-  return exec_utils->ExecAndReturnCode(cmdline, timeout_secs, timed_out, error_msg);
-}
-
-}  // namespace
-
-OdrDexopt::OdrDexopt(const OdrConfig& config, std::unique_ptr<ExecUtils> exec_utils)
-  : dex2oat_path_(config.GetDex2Oat()), exec_utils_(std::move(exec_utils)) {}
-
-int OdrDexopt::DexoptBcpExtension(const DexoptBcpExtArgs& args,
-                                  time_t timeout_secs,
-                                  /*out*/ bool* timed_out,
-                                  /*out*/ std::string* error_msg) {
-  std::vector<std::string> cmdline = { dex2oat_path_ };
-  auto result = art::AddDex2oatArgsFromBcpExtensionArgs(args, cmdline);
-  if (!result.ok()) {
-    LOG(ERROR) << "Dexopt (local) failed: " << result.error().message() << ", cmdline: "
-               << android::base::Join(cmdline, ' ');
-    return -1;
-  }
-  return ExecAndReturnCode(exec_utils_.get(), cmdline, timeout_secs, timed_out, error_msg);
-}
-
-int OdrDexopt::DexoptSystemServer(const DexoptSystemServerArgs& args,
-                                  time_t timeout_secs,
-                                  /*out*/ bool* timed_out,
-                                  /*out*/ std::string* error_msg) {
-  std::vector<std::string> cmdline = { dex2oat_path_ };
-  auto result = art::AddDex2oatArgsFromSystemServerArgs(args, cmdline);
-  if (!result.ok()) {
-    LOG(ERROR) << "Dexopt (local) failed: " << result.error().message() << ", cmdline: "
-               << android::base::Join(cmdline, ' ');
-    return -1;
-  }
-  return ExecAndReturnCode(exec_utils_.get(), cmdline, timeout_secs, timed_out, error_msg);
-}
-
-}  // namespace odrefresh
-}  // namespace art
diff --git a/odrefresh/odr_dexopt.h b/odrefresh/odr_dexopt.h
deleted file mode 100644
index 1233e8b..0000000
--- a/odrefresh/odr_dexopt.h
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (C) 2021 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_ODREFRESH_ODR_DEXOPT_H_
-#define ART_ODREFRESH_ODR_DEXOPT_H_
-
-#include <memory>
-#include <string>
-#include <time.h>
-
-#include "aidl/com/android/art/DexoptBcpExtArgs.h"
-#include "aidl/com/android/art/DexoptSystemServerArgs.h"
-
-namespace art {
-
-class ExecUtils;
-
-namespace odrefresh {
-
-using aidl::com::android::art::DexoptBcpExtArgs;
-using aidl::com::android::art::DexoptSystemServerArgs;
-
-class OdrConfig;
-
-class OdrDexopt {
- public:
-  OdrDexopt(const OdrConfig& config, std::unique_ptr<ExecUtils> exec_utils);
-
-  OdrDexopt() {}  // Test only
-
-  virtual ~OdrDexopt() {}
-
-  virtual int DexoptBcpExtension(const DexoptBcpExtArgs& args,
-                                 time_t timeout_secs,
-                                 /*out*/ bool* timed_out,
-                                 /*out*/ std::string* error_msg);
-  virtual int DexoptSystemServer(const DexoptSystemServerArgs& args,
-                                 time_t timeout_secs,
-                                 /*out*/ bool* timed_out,
-                                 /*out*/ std::string* error_msg);
-
- private:
-  std::string dex2oat_path_;
-  std::unique_ptr<ExecUtils> exec_utils_;
-};
-
-}  // namespace odrefresh
-}  // namespace art
-
-#endif  // ART_ODREFRESH_ODR_DEXOPT_H_
diff --git a/odrefresh/odrefresh.cc b/odrefresh/odrefresh.cc
index 431dd5b..b8e42f3 100644
--- a/odrefresh/odrefresh.cc
+++ b/odrefresh/odrefresh.cc
@@ -53,10 +53,6 @@
 #include <utility>
 #include <vector>
 
-#include "aidl/com/android/art/CompilerFilter.h"
-#include "aidl/com/android/art/DexoptBcpExtArgs.h"
-#include "aidl/com/android/art/DexoptSystemServerArgs.h"
-#include "aidl/com/android/art/Isa.h"
 #include "android-base/file.h"
 #include "android-base/logging.h"
 #include "android-base/macros.h"
@@ -80,13 +76,11 @@
 #include "dex/art_dex_file_loader.h"
 #include "dexoptanalyzer.h"
 #include "exec_utils.h"
-#include "libdexopt.h"
 #include "log/log.h"
 #include "odr_artifacts.h"
 #include "odr_common.h"
 #include "odr_compilation_log.h"
 #include "odr_config.h"
-#include "odr_dexopt.h"
 #include "odr_fs_utils.h"
 #include "odr_metrics.h"
 #include "odrefresh/odrefresh.h"
@@ -99,10 +93,6 @@
 namespace apex = com::android::apex;
 namespace art_apex = com::android::art;
 
-using aidl::com::android::art::CompilerFilter;
-using aidl::com::android::art::DexoptBcpExtArgs;
-using aidl::com::android::art::DexoptSystemServerArgs;
-using aidl::com::android::art::Isa;
 using android::base::Result;
 
 namespace {
@@ -364,50 +354,91 @@
   return true;
 }
 
-bool PrepareDex2OatConcurrencyArguments(/*out*/ int* threads, /*out*/ std::vector<int>* cpu_set) {
-  DCHECK(threads);
-  DCHECK(cpu_set && cpu_set->empty());
-  *threads = android::base::GetIntProperty("dalvik.vm.boot-dex2oat-threads",
-                                           /*default_value=*/0,
-                                           /*min=*/1);
+void AddDex2OatCommonOptions(/*inout*/ std::vector<std::string>& args) {
+  args.emplace_back("--android-root=out/empty");
+  args.emplace_back("--abort-on-hard-verifier-error");
+  args.emplace_back("--no-abort-on-soft-verifier-error");
+  args.emplace_back("--compilation-reason=boot");
+  args.emplace_back("--image-format=lz4");
+  args.emplace_back("--force-determinism");
+  args.emplace_back("--resolve-startup-const-strings=true");
 
-  std::string cpu_set_spec = android::base::GetProperty("dalvik.vm.boot-dex2oat-cpu-set", "");
-  if (cpu_set_spec.empty()) {
-    return true;
-  }
-  for (auto& str : android::base::Split(cpu_set_spec, ",")) {
+  // Avoid storing dex2oat cmdline in oat header. We want to be sure that the compiled artifacts
+  // are identical regardless of where the compilation happened. But some of the cmdline flags tends
+  // to be unstable, e.g. those contains FD numbers. To avoid the problem, the whole cmdline is not
+  // added to the oat header.
+  args.emplace_back("--avoid-storing-invocation");
+}
+
+bool IsCpuSetSpecValid(const std::string& cpu_set) {
+  for (auto& str : android::base::Split(cpu_set, ",")) {
     int id;
     if (!android::base::ParseInt(str, &id, 0)) {
-      LOG(ERROR) << "Invalid CPU set spec: " << cpu_set_spec;
       return false;
     }
-    cpu_set->push_back(id);
   }
   return true;
 }
 
-bool PrepareDex2OatProfileIfExists(/*inout*/ int* profile_fd,
-                                   /*inout*/ std::vector<std::unique_ptr<File>>* output_files,
-                                   const std::string& profile_path) {
-  std::unique_ptr<File> profile_file(OS::OpenFileForReading(profile_path.c_str()));
-  if (profile_file && profile_file->IsOpened()) {
-    *profile_fd = profile_file->Fd();
-    output_files->push_back(std::move(profile_file));
+bool AddDex2OatConcurrencyArguments(/*inout*/ std::vector<std::string>& args) {
+  std::string threads = android::base::GetProperty("dalvik.vm.boot-dex2oat-threads", "");
+  if (!threads.empty()) {
+    args.push_back("-j" + threads);
+  }
+
+  std::string cpu_set = android::base::GetProperty("dalvik.vm.boot-dex2oat-cpu-set", "");
+  if (cpu_set.empty()) {
     return true;
-  } else {
+  }
+  if (!IsCpuSetSpecValid(cpu_set)) {
+    LOG(ERROR) << "Invalid CPU set spec: " << cpu_set;
     return false;
   }
+  args.push_back("--cpu-set=" + cpu_set);
+  return true;
+}
+
+void AddDex2OatDebugInfo(/*inout*/ std::vector<std::string>& args) {
+  args.emplace_back("--generate-mini-debug-info");
+  args.emplace_back("--strip");
+}
+
+void AddDex2OatInstructionSet(/*inout*/ std::vector<std::string>& args, InstructionSet isa) {
+  const char* isa_str = GetInstructionSetString(isa);
+  args.emplace_back(Concatenate({"--instruction-set=", isa_str}));
+}
+
+void AddDex2OatProfileAndCompilerFilter(
+    /*inout*/ std::vector<std::string>& args,
+    /*inout*/ std::vector<std::unique_ptr<File>>& output_files,
+    const std::vector<std::string>& profile_paths) {
+  bool has_any_profile = false;
+  for (auto& path : profile_paths) {
+    std::unique_ptr<File> profile_file(OS::OpenFileForReading(path.c_str()));
+    if (profile_file && profile_file->IsOpened()) {
+      args.emplace_back(android::base::StringPrintf("--profile-file-fd=%d", profile_file->Fd()));
+      output_files.emplace_back(std::move(profile_file));
+      has_any_profile = true;
+    }
+  }
+
+  if (has_any_profile) {
+    args.emplace_back("--compiler-filter=speed-profile");
+  } else {
+    args.emplace_back("--compiler-filter=speed");
+  }
 }
 
-bool PrepareBootClasspathFds(/*inout*/ std::vector<int>& boot_classpath_fds,
-                             /*inout*/ std::vector<std::unique_ptr<File>>& output_files,
-                             const std::vector<std::string>& bcp_jars) {
+bool AddBootClasspathFds(/*inout*/ std::vector<std::string>& args,
+                         /*inout*/ std::vector<std::unique_ptr<File>>& output_files,
+                         const std::vector<std::string>& bcp_jars) {
+  std::vector<std::string> bcp_fds;
   for (const std::string& jar : bcp_jars) {
     // Special treatment for Compilation OS. JARs in staged APEX may not be visible to Android, and
     // may only be visible in the VM where the staged APEX is mounted. On the contrary, JARs in
     // /system is not available by path in the VM, and can only made available via (remote) FDs.
     if (StartsWith(jar, "/apex/")) {
-      boot_classpath_fds.emplace_back(-1);
+      bcp_fds.emplace_back("-1");
     } else {
       std::string actual_path = AndroidRootRewrite(jar);
       std::unique_ptr<File> jar_file(OS::OpenFileForReading(actual_path.c_str()));
@@ -415,10 +446,12 @@
         LOG(ERROR) << "Failed to open a BCP jar " << actual_path;
         return false;
       }
-      boot_classpath_fds.emplace_back(jar_file->Fd());
+      bcp_fds.push_back(std::to_string(jar_file->Fd()));
       output_files.push_back(std::move(jar_file));
     }
   }
+  args.emplace_back("--runtime-arg");
+  args.emplace_back(Concatenate({"-Xbootclasspathfds:", android::base::Join(bcp_fds, ':')}));
   return true;
 }
 
@@ -430,15 +463,15 @@
   return "boot-" + ReplaceFileExtension(jar_name, "art");
 }
 
-void PrepareCompiledBootClasspathFdsIfAny(
-    /*inout*/ DexoptSystemServerArgs& dexopt_args,
+void AddCompiledBootClasspathFdsIfAny(
+    /*inout*/ std::vector<std::string>& args,
     /*inout*/ std::vector<std::unique_ptr<File>>& output_files,
     const std::vector<std::string>& bcp_jars,
     const InstructionSet isa,
     const std::string& artifact_dir) {
-  std::vector<int> bcp_image_fds;
-  std::vector<int> bcp_oat_fds;
-  std::vector<int> bcp_vdex_fds;
+  std::vector<std::string> bcp_image_fds;
+  std::vector<std::string> bcp_oat_fds;
+  std::vector<std::string> bcp_vdex_fds;
   std::vector<std::unique_ptr<File>> opened_files;
   bool added_any = false;
   for (size_t i = 0; i < bcp_jars.size(); i++) {
@@ -448,40 +481,46 @@
     image_path = GetSystemImageFilename(image_path.c_str(), isa);
     std::unique_ptr<File> image_file(OS::OpenFileForReading(image_path.c_str()));
     if (image_file && image_file->IsValid()) {
-      bcp_image_fds.push_back(image_file->Fd());
+      bcp_image_fds.push_back(std::to_string(image_file->Fd()));
       opened_files.push_back(std::move(image_file));
       added_any = true;
     } else {
-      bcp_image_fds.push_back(-1);
+      bcp_image_fds.push_back("-1");
     }
 
     std::string oat_path = ReplaceFileExtension(image_path, "oat");
     std::unique_ptr<File> oat_file(OS::OpenFileForReading(oat_path.c_str()));
     if (oat_file && oat_file->IsValid()) {
-      bcp_oat_fds.push_back(oat_file->Fd());
+      bcp_oat_fds.push_back(std::to_string(oat_file->Fd()));
       opened_files.push_back(std::move(oat_file));
       added_any = true;
     } else {
-      bcp_oat_fds.push_back(-1);
+      bcp_oat_fds.push_back("-1");
     }
 
     std::string vdex_path = ReplaceFileExtension(image_path, "vdex");
     std::unique_ptr<File> vdex_file(OS::OpenFileForReading(vdex_path.c_str()));
     if (vdex_file && vdex_file->IsValid()) {
-      bcp_vdex_fds.push_back(vdex_file->Fd());
+      bcp_vdex_fds.push_back(std::to_string(vdex_file->Fd()));
       opened_files.push_back(std::move(vdex_file));
       added_any = true;
     } else {
-      bcp_vdex_fds.push_back(-1);
+      bcp_vdex_fds.push_back("-1");
     }
   }
   // Add same amount of FDs as BCP JARs, or none.
   if (added_any) {
     std::move(opened_files.begin(), opened_files.end(), std::back_inserter(output_files));
 
-    dexopt_args.bootClasspathImageFds = bcp_image_fds;
-    dexopt_args.bootClasspathVdexFds = bcp_vdex_fds;
-    dexopt_args.bootClasspathOatFds = bcp_oat_fds;
+    args.emplace_back("--runtime-arg");
+    args.emplace_back(
+        Concatenate({"-Xbootclasspathimagefds:", android::base::Join(bcp_image_fds, ':')}));
+    args.emplace_back("--runtime-arg");
+    args.emplace_back(
+        Concatenate({"-Xbootclasspathoatfds:", android::base::Join(bcp_oat_fds, ':')}));
+    args.emplace_back("--runtime-arg");
+    args.emplace_back(
+        Concatenate({"-Xbootclasspathvdexfds:", android::base::Join(bcp_vdex_fds, ':')}));
   }
 }
 
@@ -515,36 +554,6 @@
   return true;
 }
 
-Isa InstructionSetToAidlIsa(InstructionSet isa) {
-  switch (isa) {
-    case InstructionSet::kArm:
-      return Isa::ARM;
-    case InstructionSet::kThumb2:
-      return Isa::THUMB2;
-    case InstructionSet::kArm64:
-      return Isa::ARM64;
-    case InstructionSet::kX86:
-      return Isa::X86;
-    case InstructionSet::kX86_64:
-      return Isa::X86_64;
-    default:
-      UNREACHABLE();
-  }
-}
-
-CompilerFilter CompilerFilterStringToAidl(const std::string& compiler_filter) {
-  if (compiler_filter == "speed-profile") {
-    return CompilerFilter::SPEED_PROFILE;
-  } else if (compiler_filter == "speed") {
-    return CompilerFilter::SPEED;
-  } else if (compiler_filter == "verify") {
-    return CompilerFilter::VERIFY;
-  } else {
-    LOG(FATAL) << "Unrecognized compiler filter: " << compiler_filter;
-    return CompilerFilter::UNSUPPORTED;
-  }
-}
-
 std::string GetSystemBootImageDir() { return GetAndroidRoot() + "/framework"; }
 
 }  // namespace
@@ -552,18 +561,15 @@
 OnDeviceRefresh::OnDeviceRefresh(const OdrConfig& config)
     : OnDeviceRefresh(config,
                       Concatenate({config.GetArtifactDirectory(), "/", kCacheInfoFile}),
-                      std::make_unique<ExecUtils>(),
-                      std::make_unique<OdrDexopt>(config, std::make_unique<ExecUtils>())) {}
+                      std::make_unique<ExecUtils>()) {}
 
 OnDeviceRefresh::OnDeviceRefresh(const OdrConfig& config,
                                  const std::string& cache_info_filename,
-                                 std::unique_ptr<ExecUtils> exec_utils,
-                                 std::unique_ptr<OdrDexopt> odr_dexopt)
+                                 std::unique_ptr<ExecUtils> exec_utils)
     : config_{config},
       cache_info_filename_{cache_info_filename},
       start_time_{time(nullptr)},
-      exec_utils_{std::move(exec_utils)},
-      odr_dexopt_{std::move(odr_dexopt)} {
+      exec_utils_{std::move(exec_utils)} {
   for (const std::string& jar : android::base::Split(config_.GetDex2oatBootClasspath(), ":")) {
     // Updatable APEXes should not have DEX files in the DEX2OATBOOTCLASSPATH. At the time of
     // writing i18n is a non-updatable APEX and so does appear in the DEX2OATBOOTCLASSPATH.
@@ -1325,29 +1331,31 @@
     const std::function<void()>& on_dex2oat_success,
     std::string* error_msg) const {
   ScopedOdrCompilationTimer compilation_timer(metrics);
+  std::vector<std::string> args;
+  args.push_back(config_.GetDex2Oat());
 
-  DexoptBcpExtArgs dexopt_args;
-  dexopt_args.isa = InstructionSetToAidlIsa(isa);
+  AddDex2OatCommonOptions(args);
+  AddDex2OatDebugInfo(args);
+  AddDex2OatInstructionSet(args, isa);
+  if (!AddDex2OatConcurrencyArguments(args)) {
+    return false;
+  }
 
   std::vector<std::unique_ptr<File>> readonly_files_raii;
-  dexopt_args.profileFds.resize(2);
   const std::string art_boot_profile_file = GetArtRoot() + "/etc/boot-image.prof";
-  if (!PrepareDex2OatProfileIfExists(
-          &dexopt_args.profileFds[0], &readonly_files_raii, art_boot_profile_file)) {
-    LOG(ERROR) << "Missing expected ART boot profile: " << art_boot_profile_file;
-    return false;
-  }
   const std::string framework_boot_profile_file = GetAndroidRoot() + "/etc/boot-image.prof";
-  if (!PrepareDex2OatProfileIfExists(
-          &dexopt_args.profileFds[1], &readonly_files_raii, framework_boot_profile_file)) {
-    LOG(ERROR) << "Missing expected framework boot profile: " << framework_boot_profile_file;
-    return false;
-  }
+  AddDex2OatProfileAndCompilerFilter(args, readonly_files_raii,
+                                     {art_boot_profile_file, framework_boot_profile_file});
+
+  // Compile as a single image for fewer files and slightly less memory overhead.
+  args.emplace_back("--single-image");
+
+  args.emplace_back(android::base::StringPrintf("--base=0x%08x", ART_BASE_ADDRESS));
 
   const std::string dirty_image_objects_file(GetAndroidRoot() + "/etc/dirty-image-objects");
   if (OS::FileExists(dirty_image_objects_file.c_str())) {
     std::unique_ptr<File> file(OS::OpenFileForReading(dirty_image_objects_file.c_str()));
-    dexopt_args.dirtyImageObjectsFd = file->Fd();
+    args.emplace_back(android::base::StringPrintf("--dirty-image-objects-fd=%d", file->Fd()));
     readonly_files_raii.push_back(std::move(file));
   } else {
     LOG(WARNING) << "Missing dirty objects file : " << QuotePath(dirty_image_objects_file);
@@ -1356,33 +1364,34 @@
   // Add boot classpath jars to compile.
   for (const std::string& component : boot_classpath_compilable_jars_) {
     std::string actual_path = AndroidRootRewrite(component);
+    args.emplace_back("--dex-file=" + component);
     std::unique_ptr<File> file(OS::OpenFileForReading(actual_path.c_str()));
-    dexopt_args.dexPaths.emplace_back(component);
-    dexopt_args.dexFds.emplace_back(file->Fd());
+    args.emplace_back(android::base::StringPrintf("--dex-fd=%d", file->Fd()));
     readonly_files_raii.push_back(std::move(file));
   }
 
+  args.emplace_back("--runtime-arg");
+  args.emplace_back(Concatenate({"-Xbootclasspath:", config_.GetDex2oatBootClasspath()}));
   auto bcp_jars = android::base::Split(config_.GetDex2oatBootClasspath(), ":");
-  dexopt_args.bootClasspaths = bcp_jars;
-  if (!PrepareBootClasspathFds(dexopt_args.bootClasspathFds, readonly_files_raii, bcp_jars)) {
+  if (!AddBootClasspathFds(args, readonly_files_raii, bcp_jars)) {
     return false;
   }
 
   const std::string image_location = GetBootImagePath(/*on_system=*/false, isa);
   const OdrArtifacts artifacts = OdrArtifacts::ForBootImage(image_location);
 
-  dexopt_args.oatLocation = artifacts.OatPath();
-  const std::pair<const std::string, int*> location_kind_pairs[] = {
-      std::make_pair(artifacts.ImagePath(), &dexopt_args.imageFd),
-      std::make_pair(artifacts.OatPath(), &dexopt_args.oatFd),
-      std::make_pair(artifacts.VdexPath(), &dexopt_args.vdexFd)};
+  args.emplace_back("--oat-location=" + artifacts.OatPath());
+  const std::pair<const std::string, const char*> location_kind_pairs[] = {
+      std::make_pair(artifacts.ImagePath(), "image"),
+      std::make_pair(artifacts.OatPath(), "oat"),
+      std::make_pair(artifacts.VdexPath(), "output-vdex")};
   std::vector<std::unique_ptr<File>> staging_files;
   for (const auto& location_kind_pair : location_kind_pairs) {
-    auto& [location, out_ptr] = location_kind_pair;
+    auto& [location, kind] = location_kind_pair;
     const std::string staging_location = GetStagingLocation(staging_dir, location);
     std::unique_ptr<File> staging_file(OS::CreateEmptyFile(staging_location.c_str()));
     if (staging_file == nullptr) {
-      PLOG(ERROR) << "Failed to create file: " << staging_location;
+      PLOG(ERROR) << "Failed to create " << kind << " file: " << staging_location;
       metrics.SetStatus(OdrMetrics::Status::kIoError);
       EraseFiles(staging_files);
       return false;
@@ -1395,7 +1404,7 @@
       return false;
     }
 
-    *out_ptr = staging_file->Fd();
+    args.emplace_back(android::base::StringPrintf("--%s-fd=%d", kind, staging_file->Fd()));
     staging_files.emplace_back(std::move(staging_file));
   }
 
@@ -1405,24 +1414,17 @@
     return false;
   }
 
-  if (!PrepareDex2OatConcurrencyArguments(&dexopt_args.threads, &dexopt_args.cpuSet)) {
-    return false;
-  }
-
   const time_t timeout = GetSubprocessTimeout();
-  LOG(INFO) << "Compiling boot classpath (" << isa << "): " << dexopt_args.toString()
-            << " [timeout " << timeout << "s]";
+  const std::string cmd_line = android::base::Join(args, ' ');
+  LOG(INFO) << "Compiling boot classpath (" << isa << "): " << cmd_line << " [timeout " << timeout
+            << "s]";
   if (config_.GetDryRun()) {
     LOG(INFO) << "Compilation skipped (dry-run).";
     return true;
   }
 
   bool timed_out = false;
-  // NOTE: The method `DexoptBcpExtension` actually compiles the entire boot classpath. We don't
-  // rename this method because it will eventually go away.
-  // TODO(b/211977683): Call dex2oat directly.
-  int dex2oat_exit_code =
-      odr_dexopt_->DexoptBcpExtension(dexopt_args, timeout, &timed_out, error_msg);
+  int dex2oat_exit_code = exec_utils_->ExecAndReturnCode(args, timeout, &timed_out, error_msg);
 
   if (dex2oat_exit_code != 0) {
     if (timed_out) {
@@ -1466,29 +1468,29 @@
     }
 
     std::vector<std::unique_ptr<File>> readonly_files_raii;
-    DexoptSystemServerArgs dexopt_args;
-    dexopt_args.isa = InstructionSetToAidlIsa(isa);
+    std::vector<std::string> args;
+    args.emplace_back(dex2oat);
+    args.emplace_back("--dex-file=" + jar);
 
     std::string actual_jar_path = AndroidRootRewrite(jar);
     std::unique_ptr<File> dex_file(OS::OpenFileForReading(actual_jar_path.c_str()));
-
-    dexopt_args.dexPath = jar;
-    dexopt_args.dexFd = dex_file->Fd();
+    args.emplace_back(android::base::StringPrintf("--dex-fd=%d", dex_file->Fd()));
     readonly_files_raii.push_back(std::move(dex_file));
 
-    dexopt_args.isa = InstructionSetToAidlIsa(isa);
+    AddDex2OatCommonOptions(args);
+    AddDex2OatDebugInfo(args);
+    AddDex2OatInstructionSet(args, isa);
+    if (!AddDex2OatConcurrencyArguments(args)) {
+      return false;
+    }
+
     const std::string jar_name(android::base::Basename(jar));
     const std::string profile = Concatenate({GetAndroidRoot(), "/framework/", jar_name, ".prof"});
     std::string compiler_filter = config_.GetSystemServerCompilerFilter();
     if (compiler_filter == "speed-profile") {
-      // Use speed-profile only if profile is provided, otherwise fallback to speed.
-      if (PrepareDex2OatProfileIfExists(&dexopt_args.profileFd, &readonly_files_raii, profile)) {
-        dexopt_args.compilerFilter = CompilerFilter::SPEED_PROFILE;
-      } else {
-        dexopt_args.compilerFilter = CompilerFilter::SPEED;
-      }
+      AddDex2OatProfileAndCompilerFilter(args, readonly_files_raii, {profile});
     } else {
-      dexopt_args.compilerFilter = CompilerFilterStringToAidl(compiler_filter);
+      args.emplace_back("--compiler-filter=" + compiler_filter);
     }
 
     const std::string image_location = GetSystemServerImagePath(/*on_system=*/false, jar);
@@ -1501,30 +1503,32 @@
     OdrArtifacts artifacts = OdrArtifacts::ForSystemServer(image_location);
     CHECK_EQ(artifacts.OatPath(), GetApexDataOdexFilename(jar.c_str(), isa));
 
-    const std::pair<const std::string, int*> location_kind_pairs[] = {
-        std::make_pair(artifacts.ImagePath(), &dexopt_args.imageFd),
-        std::make_pair(artifacts.OatPath(), &dexopt_args.oatFd),
-        std::make_pair(artifacts.VdexPath(), &dexopt_args.vdexFd)};
+    const std::pair<const std::string, const char*> location_kind_pairs[] = {
+        std::make_pair(artifacts.ImagePath(), "app-image"),
+        std::make_pair(artifacts.OatPath(), "oat"),
+        std::make_pair(artifacts.VdexPath(), "output-vdex")};
 
     std::vector<std::unique_ptr<File>> staging_files;
     for (const auto& location_kind_pair : location_kind_pairs) {
-      auto& [location, out_ptr] = location_kind_pair;
+      auto& [location, kind] = location_kind_pair;
       const std::string staging_location = GetStagingLocation(staging_dir, location);
       std::unique_ptr<File> staging_file(OS::CreateEmptyFile(staging_location.c_str()));
       if (staging_file == nullptr) {
-        PLOG(ERROR) << "Failed to create file: " << staging_location;
+        PLOG(ERROR) << "Failed to create " << kind << " file: " << staging_location;
         metrics.SetStatus(OdrMetrics::Status::kIoError);
         EraseFiles(staging_files);
         return false;
       }
-      *out_ptr = staging_file->Fd();
+      args.emplace_back(android::base::StringPrintf("--%s-fd=%d", kind, staging_file->Fd()));
       staging_files.emplace_back(std::move(staging_file));
     }
-    dexopt_args.oatLocation = artifacts.OatPath();
+    args.emplace_back("--oat-location=" + artifacts.OatPath());
+
+    args.emplace_back("--runtime-arg");
+    args.emplace_back(Concatenate({"-Xbootclasspath:", config_.GetBootClasspath()}));
 
     auto bcp_jars = android::base::Split(config_.GetBootClasspath(), ":");
-    dexopt_args.bootClasspaths = bcp_jars;
-    if (!PrepareBootClasspathFds(dexopt_args.bootClasspathFds, readonly_files_raii, bcp_jars)) {
+    if (!AddBootClasspathFds(args, readonly_files_raii, bcp_jars)) {
       return false;
     }
     std::string unused_error_msg;
@@ -1532,17 +1536,22 @@
     // and the artifacts must exist on /system.
     bool boot_image_on_system =
         !BootClasspathArtifactsExist(/*on_system=*/false, isa, &unused_error_msg);
-    PrepareCompiledBootClasspathFdsIfAny(
-        dexopt_args,
+    AddCompiledBootClasspathFdsIfAny(
+        args,
         readonly_files_raii,
         bcp_jars,
         isa,
         boot_image_on_system ? GetSystemBootImageDir() : config_.GetArtifactDirectory());
-    dexopt_args.bootImage = boot_image_on_system ? GetBootImage(/*on_system=*/true) + ":" +
-                                                       GetSystemBootImageExtension() :
-                                                   GetBootImage(/*on_system=*/false);
+    args.emplace_back(Concatenate({"--boot-image=", boot_image_on_system
+        ? GetBootImage(/*on_system=*/true) + ":" + GetSystemBootImageExtension()
+        : GetBootImage(/*on_system=*/false)}));
 
-    dexopt_args.classloaderContext = classloader_context;
+    const std::string context_path = android::base::Join(classloader_context, ':');
+    if (art::ContainsElement(systemserver_classpath_jars_, jar)) {
+      args.emplace_back("--class-loader-context=PCL[" + context_path + "]");
+    } else {
+      args.emplace_back("--class-loader-context=PCL[];PCL[" + context_path + "]");
+    }
     if (!classloader_context.empty()) {
       std::vector<int> fds;
       for (const std::string& path : classloader_context) {
@@ -1556,27 +1565,20 @@
         fds.emplace_back(file->Fd());
         readonly_files_raii.emplace_back(std::move(file));
       }
-      dexopt_args.classloaderFds = fds;
-    }
-    if (!art::ContainsElement(systemserver_classpath_jars_, jar)) {
-      dexopt_args.classloaderContextAsParent = true;
-    }
-
-    if (!PrepareDex2OatConcurrencyArguments(&dexopt_args.threads, &dexopt_args.cpuSet)) {
-      return false;
+      const std::string context_fds = android::base::Join(fds, ':');
+      args.emplace_back(Concatenate({"--class-loader-context-fds=", context_fds}));
     }
 
     const time_t timeout = GetSubprocessTimeout();
-    LOG(INFO) << "Compiling " << jar << ": " << dexopt_args.toString() << " [timeout " << timeout
-              << "s]";
+    const std::string cmd_line = android::base::Join(args, ' ');
+    LOG(INFO) << "Compiling " << jar << ": " << cmd_line << " [timeout " << timeout << "s]";
     if (config_.GetDryRun()) {
       LOG(INFO) << "Compilation skipped (dry-run).";
       return true;
     }
 
     bool timed_out = false;
-    int dex2oat_exit_code =
-        odr_dexopt_->DexoptSystemServer(dexopt_args, timeout, &timed_out, error_msg);
+    int dex2oat_exit_code = exec_utils_->ExecAndReturnCode(args, timeout, &timed_out, error_msg);
 
     if (dex2oat_exit_code != 0) {
       if (timed_out) {
diff --git a/odrefresh/odrefresh.h b/odrefresh/odrefresh.h
index d749b2b..21e5f61 100644
--- a/odrefresh/odrefresh.h
+++ b/odrefresh/odrefresh.h
@@ -32,7 +32,6 @@
 #include "exec_utils.h"
 #include "odr_artifacts.h"
 #include "odr_config.h"
-#include "odr_dexopt.h"
 #include "odr_metrics.h"
 #include "odrefresh/odrefresh.h"
 
@@ -57,8 +56,7 @@
   // Constructor with injections. For testing and internal use only.
   OnDeviceRefresh(const OdrConfig& config,
                   const std::string& cache_info_filename,
-                  std::unique_ptr<ExecUtils> exec_utils,
-                  std::unique_ptr<OdrDexopt> odr_dexopt);
+                  std::unique_ptr<ExecUtils> exec_utils);
 
   // Returns the exit code and specifies what should be compiled in `compilation_options`.
   WARN_UNUSED ExitCode
@@ -200,8 +198,6 @@
 
   std::unique_ptr<ExecUtils> exec_utils_;
 
-  std::unique_ptr<OdrDexopt> odr_dexopt_;
-
   DISALLOW_COPY_AND_ASSIGN(OnDeviceRefresh);
 };
 
diff --git a/odrefresh/odrefresh_test.cc b/odrefresh/odrefresh_test.cc
index 60abcd5..35c4c2d 100644
--- a/odrefresh/odrefresh_test.cc
+++ b/odrefresh/odrefresh_test.cc
@@ -24,10 +24,6 @@
 #include <utility>
 #include <vector>
 
-#include "aidl/com/android/art/CompilerFilter.h"
-#include "aidl/com/android/art/DexoptBcpExtArgs.h"
-#include "aidl/com/android/art/DexoptSystemServerArgs.h"
-#include "aidl/com/android/art/Isa.h"
 #include "android-base/file.h"
 #include "android-base/parseint.h"
 #include "android-base/scopeguard.h"
@@ -43,7 +39,6 @@
 #include "odr_artifacts.h"
 #include "odr_common.h"
 #include "odr_config.h"
-#include "odr_dexopt.h"
 #include "odr_fs_utils.h"
 #include "odr_metrics.h"
 #include "odrefresh/odrefresh.h"
@@ -51,18 +46,10 @@
 namespace art {
 namespace odrefresh {
 
-using ::aidl::com::android::art::CompilerFilter;
-using ::aidl::com::android::art::DexoptBcpExtArgs;
-using ::aidl::com::android::art::DexoptSystemServerArgs;
-using ::aidl::com::android::art::Isa;
 using ::testing::_;
 using ::testing::AllOf;
 using ::testing::Contains;
-using ::testing::ElementsAre;
-using ::testing::Eq;
-using ::testing::Field;
-using ::testing::Ge;
-using ::testing::IsEmpty;
+using ::testing::HasSubstr;
 using ::testing::Return;
 
 constexpr int kReplace = 1;
@@ -79,26 +66,42 @@
   return android::base::ScopeGuard([=]() { unlink(name.c_str()); });
 }
 
-class MockOdrDexopt : public OdrDexopt {
+class MockExecUtils : public ExecUtils {
  public:
   // A workaround to avoid MOCK_METHOD on a method with an `std::string*` parameter, which will lead
   // to a conflict between gmock and android-base/logging.h (b/132668253).
-  int DexoptBcpExtension(const DexoptBcpExtArgs& args, time_t, bool*, std::string*) override {
-    return DoDexoptBcpExtension(args);
+  int ExecAndReturnCode(std::vector<std::string>& arg_vector,
+                        time_t,
+                        bool*,
+                        std::string*) const override {
+    return DoExecAndReturnCode(arg_vector);
   }
 
-  int DexoptSystemServer(const DexoptSystemServerArgs& args, time_t, bool*, std::string*) override {
-    return DoDexoptSystemServer(args);
-  }
-
-  MOCK_METHOD(int, DoDexoptBcpExtension, (const DexoptBcpExtArgs&));
-  MOCK_METHOD(int, DoDexoptSystemServer, (const DexoptSystemServerArgs&));
+  MOCK_METHOD(int, DoExecAndReturnCode, (std::vector<std::string> & arg_vector), (const));
 };
 
+// Matches a flag that starts with `flag` and is a colon-separated list that contains an element
+// that matches `matcher`.
+MATCHER_P2(FlagContains, flag, matcher, "") {
+  std::string_view value = arg;
+  if (!android::base::ConsumePrefix(&value, flag)) {
+    return false;
+  }
+  for (std::string_view s : SplitString(value, ':')) {
+    if (ExplainMatchResult(matcher, s, result_listener)) {
+      return true;
+    }
+  }
+  return false;
+}
+
 // Matches an FD of a file whose path matches `matcher`.
 MATCHER_P(FdOf, matcher, "") {
   char path[PATH_MAX];
-  int fd = arg;
+  int fd;
+  if (!android::base::ParseInt(std::string{arg}, &fd)) {
+    return false;
+  }
   std::string proc_path = android::base::StringPrintf("/proc/self/fd/%d", fd);
   ssize_t len = readlink(proc_path.c_str(), path, sizeof(path));
   if (len < 0) {
@@ -205,7 +208,12 @@
     ASSERT_TRUE(EnsureDirectoryExists(staging_dir));
     config_.SetStagingDir(staging_dir);
 
+    auto mock_exec_utils = std::make_unique<MockExecUtils>();
+    mock_exec_utils_ = mock_exec_utils.get();
+
     metrics_ = std::make_unique<OdrMetrics>(dalvik_cache_dir_);
+    odrefresh_ = std::make_unique<OnDeviceRefresh>(
+        config_, dalvik_cache_dir_ + "/cache-info.xml", std::move(mock_exec_utils));
   }
 
   void TearDown() override {
@@ -218,21 +226,13 @@
     CommonArtTest::TearDown();
   }
 
-  std::pair<std::unique_ptr<OnDeviceRefresh>, MockOdrDexopt*> CreateOdRefresh() {
-    auto mock_odr_dexopt = std::make_unique<MockOdrDexopt>();
-    MockOdrDexopt* mock_odr_dexopt_ptr = mock_odr_dexopt.get();
-    auto odrefresh = std::make_unique<OnDeviceRefresh>(config_,
-                                                       dalvik_cache_dir_ + "/cache-info.xml",
-                                                       std::make_unique<ExecUtils>(),
-                                                       std::move(mock_odr_dexopt));
-    return std::make_pair(std::move(odrefresh), mock_odr_dexopt_ptr);
-  }
-
   std::unique_ptr<ScratchDir> temp_dir_;
   std::unique_ptr<ScopedUnsetEnvironmentVariable> android_root_env_;
   std::unique_ptr<ScopedUnsetEnvironmentVariable> android_art_root_env_;
   std::unique_ptr<ScopedUnsetEnvironmentVariable> art_apex_data_env_;
   OdrConfig config_;
+  MockExecUtils* mock_exec_utils_;
+  std::unique_ptr<OnDeviceRefresh> odrefresh_;
   std::unique_ptr<OdrMetrics> metrics_;
   std::string core_oj_jar_;
   std::string framework_jar_;
@@ -248,88 +248,77 @@
 };
 
 TEST_F(OdRefreshTest, BootClasspathJars) {
-  auto [odrefresh, mock_odr_dexopt] = CreateOdRefresh();
-
-  EXPECT_CALL(*mock_odr_dexopt,
-              DoDexoptBcpExtension(AllOf(
-                  Field(&DexoptBcpExtArgs::dexPaths, ElementsAre(core_oj_jar_, framework_jar_)),
-                  AllOf(Field(&DexoptBcpExtArgs::dexFds,
-                              ElementsAre(FdOf(core_oj_jar_), FdOf(framework_jar_))),
-                        Field(&DexoptBcpExtArgs::profileFds,
-                              ElementsAre(FdOf(art_profile_), FdOf(framework_profile_))),
-                        Field(&DexoptBcpExtArgs::oatLocation,
-                              Eq(dalvik_cache_dir_ + "/x86_64/boot.oat"))))))
+  EXPECT_CALL(*mock_exec_utils_,
+              DoExecAndReturnCode(AllOf(
+                  Contains(Concatenate({"--dex-file=", core_oj_jar_})),
+                  Contains(Concatenate({"--dex-file=", framework_jar_})),
+                  Contains(FlagContains("--dex-fd=", FdOf(core_oj_jar_))),
+                  Contains(FlagContains("--dex-fd=", FdOf(framework_jar_))),
+                  Contains(FlagContains("--profile-file-fd=", FdOf(art_profile_))),
+                  Contains(FlagContains("--profile-file-fd=", FdOf(framework_profile_))),
+                  Contains(Concatenate({"--oat-location=", dalvik_cache_dir_, "/x86_64/boot.oat"})),
+                  Contains(HasSubstr("--base=")),
+                  Contains("--compiler-filter=speed-profile"))))
       .WillOnce(Return(0));
 
-  EXPECT_EQ(odrefresh->Compile(*metrics_,
-                               CompilationOptions{
-                                   .compile_boot_classpath_for_isas = {InstructionSet::kX86_64},
-                               }),
+  EXPECT_EQ(odrefresh_->Compile(*metrics_,
+                                CompilationOptions{
+                                    .compile_boot_classpath_for_isas = {InstructionSet::kX86_64},
+                                }),
             ExitCode::kCompilationSuccess);
 }
 
 TEST_F(OdRefreshTest, AllSystemServerJars) {
-  auto [odrefresh, mock_odr_dexopt] = CreateOdRefresh();
-
-  EXPECT_CALL(*mock_odr_dexopt,
-              DoDexoptSystemServer(
-                  AllOf(Field(&DexoptSystemServerArgs::dexPath, Eq(location_provider_jar_)),
-                        Field(&DexoptSystemServerArgs::classloaderContext, IsEmpty()),
-                        Field(&DexoptSystemServerArgs::classloaderContextAsParent, Eq(false)))))
+  EXPECT_CALL(*mock_exec_utils_,
+              DoExecAndReturnCode(AllOf(
+                  Contains(Concatenate({"--dex-file=", location_provider_jar_})),
+                  Contains("--class-loader-context=PCL[]"))))
       .WillOnce(Return(0));
-  EXPECT_CALL(
-      *mock_odr_dexopt,
-      DoDexoptSystemServer(AllOf(
-          Field(&DexoptSystemServerArgs::dexPath, Eq(services_jar_)),
-          Field(&DexoptSystemServerArgs::classloaderContext, ElementsAre(location_provider_jar_)),
-          Field(&DexoptSystemServerArgs::classloaderContextAsParent, Eq(false)))))
+  EXPECT_CALL(*mock_exec_utils_,
+              DoExecAndReturnCode(AllOf(
+                  Contains(Concatenate({"--dex-file=", services_jar_})),
+                  Contains(Concatenate({"--class-loader-context=PCL[", location_provider_jar_,
+                                        "]"})))))
       .WillOnce(Return(0));
-  EXPECT_CALL(*mock_odr_dexopt,
-              DoDexoptSystemServer(
-                  AllOf(Field(&DexoptSystemServerArgs::dexPath, Eq(services_foo_jar_)),
-                        Field(&DexoptSystemServerArgs::classloaderContext,
-                              ElementsAre(location_provider_jar_, services_jar_)),
-                        Field(&DexoptSystemServerArgs::classloaderContextAsParent, Eq(true)))))
+  EXPECT_CALL(*mock_exec_utils_,
+              DoExecAndReturnCode(AllOf(
+                  Contains(Concatenate({"--dex-file=", services_foo_jar_})),
+                  Contains(Concatenate({"--class-loader-context=PCL[];PCL[", location_provider_jar_,
+                                        ":", services_jar_, "]"})))))
       .WillOnce(Return(0));
-  EXPECT_CALL(*mock_odr_dexopt,
-              DoDexoptSystemServer(
-                  AllOf(Field(&DexoptSystemServerArgs::dexPath, Eq(services_bar_jar_)),
-                        Field(&DexoptSystemServerArgs::classloaderContext,
-                              ElementsAre(location_provider_jar_, services_jar_)),
-                        Field(&DexoptSystemServerArgs::classloaderContextAsParent, Eq(true)))))
+  EXPECT_CALL(*mock_exec_utils_,
+              DoExecAndReturnCode(AllOf(
+                  Contains(Concatenate({"--dex-file=", services_bar_jar_})),
+                  Contains(Concatenate({"--class-loader-context=PCL[];PCL[", location_provider_jar_,
+                                        ":", services_jar_, "]"})))))
       .WillOnce(Return(0));
 
   EXPECT_EQ(
-      odrefresh->Compile(*metrics_,
-                         CompilationOptions{
-                             .system_server_jars_to_compile = odrefresh->AllSystemServerJars(),
-                         }),
+      odrefresh_->Compile(*metrics_,
+                          CompilationOptions{
+                              .system_server_jars_to_compile = odrefresh_->AllSystemServerJars(),
+                          }),
       ExitCode::kCompilationSuccess);
 }
 
 TEST_F(OdRefreshTest, PartialSystemServerJars) {
-  auto [odrefresh, mock_odr_dexopt] = CreateOdRefresh();
-
-  EXPECT_CALL(
-      *mock_odr_dexopt,
-      DoDexoptSystemServer(AllOf(
-          Field(&DexoptSystemServerArgs::dexPath, Eq(services_jar_)),
-          Field(&DexoptSystemServerArgs::classloaderContext, ElementsAre(location_provider_jar_)),
-          Field(&DexoptSystemServerArgs::classloaderContextAsParent, Eq(false)))))
+  EXPECT_CALL(*mock_exec_utils_,
+              DoExecAndReturnCode(AllOf(
+                  Contains(Concatenate({"--dex-file=", services_jar_})),
+                  Contains(Concatenate({"--class-loader-context=PCL[", location_provider_jar_, "]"})))))
       .WillOnce(Return(0));
-  EXPECT_CALL(*mock_odr_dexopt,
-              DoDexoptSystemServer(
-                  AllOf(Field(&DexoptSystemServerArgs::dexPath, Eq(services_bar_jar_)),
-                        Field(&DexoptSystemServerArgs::classloaderContext,
-                              ElementsAre(location_provider_jar_, services_jar_)),
-                        Field(&DexoptSystemServerArgs::classloaderContextAsParent, Eq(true)))))
+  EXPECT_CALL(*mock_exec_utils_,
+              DoExecAndReturnCode(AllOf(
+                  Contains(Concatenate({"--dex-file=", services_bar_jar_})),
+                  Contains(Concatenate({"--class-loader-context=PCL[];PCL[", location_provider_jar_,
+                                        ":", services_jar_, "]"})))))
       .WillOnce(Return(0));
 
   EXPECT_EQ(
-      odrefresh->Compile(*metrics_,
-                         CompilationOptions{
-                             .system_server_jars_to_compile = {services_jar_, services_bar_jar_},
-                         }),
+      odrefresh_->Compile(*metrics_,
+                          CompilationOptions{
+                              .system_server_jars_to_compile = {services_jar_, services_bar_jar_},
+                          }),
       ExitCode::kCompilationSuccess);
 }
 
@@ -337,205 +326,187 @@
 // missing, which is expected on Android S.
 TEST_F(OdRefreshTest, MissingStandaloneSystemServerJars) {
   config_.SetStandaloneSystemServerJars("");
-  auto [odrefresh, mock_odr_dexopt] = CreateOdRefresh();
-  EXPECT_CALL(*mock_odr_dexopt, DoDexoptSystemServer).WillRepeatedly(Return(0));
+  EXPECT_CALL(*mock_exec_utils_, DoExecAndReturnCode(_)).WillRepeatedly(Return(0));
   EXPECT_EQ(
-      odrefresh->Compile(*metrics_,
-                         CompilationOptions{
-                             .system_server_jars_to_compile = odrefresh->AllSystemServerJars(),
-                         }),
+      odrefresh_->Compile(*metrics_,
+                          CompilationOptions{
+                              .system_server_jars_to_compile = odrefresh_->AllSystemServerJars(),
+                          }),
       ExitCode::kCompilationSuccess);
 }
 
-TEST_F(OdRefreshTest, CompileSetsCompilerFilter) {
-  {
-    auto [odrefresh, mock_odr_dexopt] = CreateOdRefresh();
+TEST_F(OdRefreshTest, CompileSetsCompilerFilterToSpeed) {
+  // Test setup: use "speed" compiler filter.
+  config_.SetSystemServerCompilerFilter("speed");
 
-    // Test setup: use "speed" compiler filter.
-    config_.SetSystemServerCompilerFilter("speed");
+  // Uninteresting calls.
+  EXPECT_CALL(
+      *mock_exec_utils_, DoExecAndReturnCode(_))
+      .Times(odrefresh_->AllSystemServerJars().size() - 2)
+      .WillRepeatedly(Return(0));
 
-    // Uninteresting calls.
-    EXPECT_CALL(*mock_odr_dexopt, DoDexoptSystemServer(_))
-        .Times(odrefresh->AllSystemServerJars().size() - 2)
-        .WillRepeatedly(Return(0))
-        .RetiresOnSaturation();
+  EXPECT_CALL(
+      *mock_exec_utils_,
+      DoExecAndReturnCode(AllOf(Contains(Concatenate({"--dex-file=", location_provider_jar_})),
+                                Not(Contains(HasSubstr("--profile-file-fd="))),
+                                Contains("--compiler-filter=speed"))))
+      .WillOnce(Return(0));
+  EXPECT_CALL(
+      *mock_exec_utils_,
+      DoExecAndReturnCode(AllOf(Contains(Concatenate({"--dex-file=", services_jar_})),
+                                Not(Contains(HasSubstr("--profile-file-fd="))),
+                                Contains("--compiler-filter=speed"))))
+      .WillOnce(Return(0));
+  EXPECT_EQ(
+      odrefresh_->Compile(*metrics_,
+                          CompilationOptions{
+                            .system_server_jars_to_compile = odrefresh_->AllSystemServerJars(),
+                          }),
+      ExitCode::kCompilationSuccess);
+}
 
-    EXPECT_CALL(*mock_odr_dexopt,
-                DoDexoptSystemServer(AllOf(
-                    Field(&DexoptSystemServerArgs::dexPath, Eq(location_provider_jar_)),
-                    Field(&DexoptSystemServerArgs::compilerFilter, Eq(CompilerFilter::SPEED)))))
-        .WillOnce(Return(0))
-        .RetiresOnSaturation();
-    EXPECT_CALL(*mock_odr_dexopt,
-                DoDexoptSystemServer(AllOf(
-                    Field(&DexoptSystemServerArgs::dexPath, Eq(services_jar_)),
-                    Field(&DexoptSystemServerArgs::compilerFilter, Eq(CompilerFilter::SPEED)))))
-        .WillOnce(Return(0))
-        .RetiresOnSaturation();
-    EXPECT_EQ(
-        odrefresh->Compile(*metrics_,
-                           CompilationOptions{
-                               .system_server_jars_to_compile = odrefresh->AllSystemServerJars(),
-                           }),
-        ExitCode::kCompilationSuccess);
-  }
+TEST_F(OdRefreshTest, CompileSetsCompilerFilterToSpeedProfile) {
+  // Test setup: with "speed-profile" compiler filter in the request, only apply if there is a
+  // profile, otherwise fallback to speed.
+  config_.SetSystemServerCompilerFilter("speed-profile");
 
-  {
-    auto [odrefresh, mock_odr_dexopt] = CreateOdRefresh();
+  // Uninteresting calls.
+  EXPECT_CALL(
+      *mock_exec_utils_, DoExecAndReturnCode(_))
+      .Times(odrefresh_->AllSystemServerJars().size() - 2)
+      .WillRepeatedly(Return(0));
 
-    // Test setup: with "speed-profile" compiler filter in the request, only apply if there is a
-    // profile, otherwise fallback to speed.
-    config_.SetSystemServerCompilerFilter("speed-profile");
+  // services.jar has a profile, while location.provider.jar does not.
+  EXPECT_CALL(
+      *mock_exec_utils_,
+      DoExecAndReturnCode(AllOf(Contains(Concatenate({"--dex-file=", location_provider_jar_})),
+                                Not(Contains(HasSubstr("--profile-file-fd="))),
+                                Contains("--compiler-filter=speed"))))
+      .WillOnce(Return(0));
+  EXPECT_CALL(
+      *mock_exec_utils_,
+      DoExecAndReturnCode(AllOf(Contains(Concatenate({"--dex-file=", services_jar_})),
+                                Contains(HasSubstr("--profile-file-fd=")),
+                                Contains("--compiler-filter=speed-profile"))))
+      .WillOnce(Return(0));
+  EXPECT_EQ(
+      odrefresh_->Compile(*metrics_,
+                          CompilationOptions{
+                            .system_server_jars_to_compile = odrefresh_->AllSystemServerJars(),
+                          }),
+      ExitCode::kCompilationSuccess);
+}
 
-    // Uninteresting calls.
-    EXPECT_CALL(*mock_odr_dexopt, DoDexoptSystemServer(_))
-        .Times(odrefresh->AllSystemServerJars().size() - 2)
-        .WillRepeatedly(Return(0))
-        .RetiresOnSaturation();
+TEST_F(OdRefreshTest, CompileSetsCompilerFilterToVerify) {
+  // Test setup: use "speed" compiler filter.
+  config_.SetSystemServerCompilerFilter("verify");
 
-    // services.jar has a profile, while location.provider.jar does not.
-    EXPECT_CALL(
-        *mock_odr_dexopt,
-        DoDexoptSystemServer(AllOf(
-            Field(&DexoptSystemServerArgs::dexPath, Eq(services_jar_)),
-            Field(&DexoptSystemServerArgs::profileFd, Ge(0)),
-            Field(&DexoptSystemServerArgs::compilerFilter, Eq(CompilerFilter::SPEED_PROFILE)))))
-        .WillOnce(Return(0))
-        .RetiresOnSaturation();
-    EXPECT_CALL(*mock_odr_dexopt,
-                DoDexoptSystemServer(AllOf(
-                    Field(&DexoptSystemServerArgs::dexPath, Eq(location_provider_jar_)),
-                    Field(&DexoptSystemServerArgs::compilerFilter, Eq(CompilerFilter::SPEED)))))
-        .WillOnce(Return(0))
-        .RetiresOnSaturation();
-    EXPECT_EQ(
-        odrefresh->Compile(*metrics_,
-                           CompilationOptions{
-                               .system_server_jars_to_compile = odrefresh->AllSystemServerJars(),
-                           }),
-        ExitCode::kCompilationSuccess);
-  }
+  // Uninteresting calls.
+  EXPECT_CALL(
+      *mock_exec_utils_, DoExecAndReturnCode(_))
+      .Times(odrefresh_->AllSystemServerJars().size() - 2)
+      .WillRepeatedly(Return(0));
 
-  {
-    auto [odrefresh, mock_odr_dexopt] = CreateOdRefresh();
-
-    // Test setup: "verify" compiler filter should be simply applied.
-    config_.SetSystemServerCompilerFilter("verify");
-
-    // Uninteresting calls.
-    EXPECT_CALL(*mock_odr_dexopt, DoDexoptSystemServer(_))
-        .Times(odrefresh->AllSystemServerJars().size() - 2)
-        .WillRepeatedly(Return(0))
-        .RetiresOnSaturation();
-
-    EXPECT_CALL(*mock_odr_dexopt,
-                DoDexoptSystemServer(AllOf(
-                    Field(&DexoptSystemServerArgs::dexPath, Eq(location_provider_jar_)),
-                    Field(&DexoptSystemServerArgs::compilerFilter, Eq(CompilerFilter::VERIFY)))))
-        .WillOnce(Return(0))
-        .RetiresOnSaturation();
-    EXPECT_CALL(*mock_odr_dexopt,
-                DoDexoptSystemServer(AllOf(
-                    Field(&DexoptSystemServerArgs::dexPath, Eq(services_jar_)),
-                    Field(&DexoptSystemServerArgs::compilerFilter, Eq(CompilerFilter::VERIFY)))))
-        .WillOnce(Return(0))
-        .RetiresOnSaturation();
-    EXPECT_EQ(
-        odrefresh->Compile(*metrics_,
-                           CompilationOptions{
-                               .system_server_jars_to_compile = odrefresh->AllSystemServerJars(),
-                           }),
-        ExitCode::kCompilationSuccess);
-  }
+  EXPECT_CALL(
+      *mock_exec_utils_,
+      DoExecAndReturnCode(AllOf(Contains(Concatenate({"--dex-file=", location_provider_jar_})),
+                                Not(Contains(HasSubstr("--profile-file-fd="))),
+                                Contains("--compiler-filter=verify"))))
+      .WillOnce(Return(0));
+  EXPECT_CALL(
+      *mock_exec_utils_,
+      DoExecAndReturnCode(AllOf(Contains(Concatenate({"--dex-file=", services_jar_})),
+                                Not(Contains(HasSubstr("--profile-file-fd="))),
+                                Contains("--compiler-filter=verify"))))
+      .WillOnce(Return(0));
+  EXPECT_EQ(
+      odrefresh_->Compile(*metrics_,
+                          CompilationOptions{
+                              .system_server_jars_to_compile = odrefresh_->AllSystemServerJars(),
+                          }),
+      ExitCode::kCompilationSuccess);
 }
 
 TEST_F(OdRefreshTest, OutputFilesAndIsa) {
-  auto [odrefresh, mock_odr_dexopt] = CreateOdRefresh();
-
-  EXPECT_CALL(*mock_odr_dexopt,
-              DoDexoptBcpExtension(AllOf(Field(&DexoptBcpExtArgs::isa, Eq(Isa::X86_64)),
-                                         Field(&DexoptBcpExtArgs::imageFd, Ge(0)),
-                                         Field(&DexoptBcpExtArgs::vdexFd, Ge(0)),
-                                         Field(&DexoptBcpExtArgs::oatFd, Ge(0)))))
+  EXPECT_CALL(
+      *mock_exec_utils_,
+      DoExecAndReturnCode(AllOf(Contains("--instruction-set=x86_64"),
+                                Contains(HasSubstr("--image-fd=")),
+                                Contains(HasSubstr("--output-vdex-fd=")),
+                                Contains(HasSubstr("--oat-fd=")))))
       .WillOnce(Return(0));
 
-  EXPECT_CALL(*mock_odr_dexopt,
-              DoDexoptSystemServer(AllOf(Field(&DexoptSystemServerArgs::isa, Eq(Isa::X86_64)),
-                                         Field(&DexoptSystemServerArgs::imageFd, Ge(0)),
-                                         Field(&DexoptSystemServerArgs::vdexFd, Ge(0)),
-                                         Field(&DexoptSystemServerArgs::oatFd, Ge(0)))))
-      .Times(odrefresh->AllSystemServerJars().size())
+  EXPECT_CALL(
+      *mock_exec_utils_,
+      DoExecAndReturnCode(AllOf(Contains("--instruction-set=x86_64"),
+                                Contains(HasSubstr("--app-image-fd=")),
+                                Contains(HasSubstr("--output-vdex-fd=")),
+                                Contains(HasSubstr("--oat-fd=")))))
+      .Times(odrefresh_->AllSystemServerJars().size())
       .WillRepeatedly(Return(0));
 
   EXPECT_EQ(
-      odrefresh->Compile(*metrics_,
-                         CompilationOptions{
-                             .compile_boot_classpath_for_isas = {InstructionSet::kX86_64},
-                             .system_server_jars_to_compile = odrefresh->AllSystemServerJars(),
-                         }),
+      odrefresh_->Compile(*metrics_,
+                          CompilationOptions{
+                            .compile_boot_classpath_for_isas = {InstructionSet::kX86_64},
+                            .system_server_jars_to_compile = odrefresh_->AllSystemServerJars(),
+                          }),
       ExitCode::kCompilationSuccess);
 }
 
-TEST_F(OdRefreshTest, CompileChoosesBootImage) {
-  {
-    auto [odrefresh, mock_odr_dexopt] = CreateOdRefresh();
+TEST_F(OdRefreshTest, CompileChoosesBootImage_OnData) {
+  // Boot image is on /data.
+  OdrArtifacts artifacts = OdrArtifacts::ForBootImage(dalvik_cache_dir_ + "/x86_64/boot.art");
+  auto file1 = ScopedCreateEmptyFile(artifacts.ImagePath());
+  auto file2 = ScopedCreateEmptyFile(artifacts.VdexPath());
+  auto file3 = ScopedCreateEmptyFile(artifacts.OatPath());
 
-    // Boot image is on /data.
-    OdrArtifacts artifacts = OdrArtifacts::ForBootImage(dalvik_cache_dir_ + "/x86_64/boot.art");
-    auto file1 = ScopedCreateEmptyFile(artifacts.ImagePath());
-    auto file2 = ScopedCreateEmptyFile(artifacts.VdexPath());
-    auto file3 = ScopedCreateEmptyFile(artifacts.OatPath());
+  EXPECT_CALL(
+      *mock_exec_utils_,
+      DoExecAndReturnCode(AllOf(
+          Contains(Concatenate({"--boot-image=", dalvik_cache_dir_, "/boot.art"})),
+          Contains(FlagContains("-Xbootclasspathimagefds:", FdOf(artifacts.ImagePath()))),
+          Contains(FlagContains("-Xbootclasspathvdexfds:", FdOf(artifacts.VdexPath()))),
+          Contains(FlagContains("-Xbootclasspathoatfds:", FdOf(artifacts.OatPath()))))))
+      .Times(odrefresh_->AllSystemServerJars().size())
+      .WillRepeatedly(Return(0));
+  EXPECT_EQ(
+      odrefresh_->Compile(*metrics_,
+                          CompilationOptions{
+                            .system_server_jars_to_compile = odrefresh_->AllSystemServerJars(),
+                          }),
+      ExitCode::kCompilationSuccess);
+}
 
-    EXPECT_CALL(*mock_odr_dexopt,
-                DoDexoptSystemServer(AllOf(
-                    Field(&DexoptSystemServerArgs::bootImage, Eq(dalvik_cache_dir_ + "/boot.art")),
-                    Field(&DexoptSystemServerArgs::bootClasspathImageFds,
-                          Contains(FdOf(artifacts.ImagePath()))),
-                    Field(&DexoptSystemServerArgs::bootClasspathVdexFds,
-                          Contains(FdOf(artifacts.VdexPath()))),
-                    Field(&DexoptSystemServerArgs::bootClasspathOatFds,
-                          Contains(FdOf(artifacts.OatPath()))))))
-        .Times(odrefresh->AllSystemServerJars().size())
-        .WillRepeatedly(Return(0));
-    EXPECT_EQ(
-        odrefresh->Compile(*metrics_,
-                           CompilationOptions{
-                               .system_server_jars_to_compile = odrefresh->AllSystemServerJars(),
-                           }),
-        ExitCode::kCompilationSuccess);
-  }
+TEST_F(OdRefreshTest, CompileChoosesBootImage_OnSystem) {
+  // Boot image is on /system.
+  OdrArtifacts artifacts =
+      OdrArtifacts::ForBootImage(framework_dir_ + "/x86_64/boot-framework.art");
+  auto file1 = ScopedCreateEmptyFile(artifacts.ImagePath());
+  auto file2 = ScopedCreateEmptyFile(artifacts.VdexPath());
+  auto file3 = ScopedCreateEmptyFile(artifacts.OatPath());
 
-  {
-    auto [odrefresh, mock_odr_dexopt] = CreateOdRefresh();
-
-    // Boot image is on /system.
-    OdrArtifacts artifacts =
-        OdrArtifacts::ForBootImage(framework_dir_ + "/x86_64/boot-framework.art");
-    auto file1 = ScopedCreateEmptyFile(artifacts.ImagePath());
-    auto file2 = ScopedCreateEmptyFile(artifacts.VdexPath());
-    auto file3 = ScopedCreateEmptyFile(artifacts.OatPath());
-
-    EXPECT_CALL(*mock_odr_dexopt,
-                DoDexoptSystemServer(AllOf(
-                    Field(&DexoptSystemServerArgs::bootImage,
-                          Eq(android::base::StringPrintf("%s/boot.art:%s/boot-framework.art",
-                                                         GetPrebuiltPrimaryBootImageDir().c_str(),
-                                                         framework_dir_.c_str()))),
-                    Field(&DexoptSystemServerArgs::bootClasspathImageFds,
-                          Contains(FdOf(artifacts.ImagePath()))),
-                    Field(&DexoptSystemServerArgs::bootClasspathVdexFds,
-                          Contains(FdOf(artifacts.VdexPath()))),
-                    Field(&DexoptSystemServerArgs::bootClasspathOatFds,
-                          Contains(FdOf(artifacts.OatPath()))))))
-        .Times(odrefresh->AllSystemServerJars().size())
-        .WillRepeatedly(Return(0));
-    EXPECT_EQ(
-        odrefresh->Compile(*metrics_,
-                           CompilationOptions{
-                               .system_server_jars_to_compile = odrefresh->AllSystemServerJars(),
-                           }),
-        ExitCode::kCompilationSuccess);
-  }
+  // Ignore the execution for compiling the boot classpath.
+  EXPECT_CALL(
+      *mock_exec_utils_, DoExecAndReturnCode(Contains(HasSubstr("--image-fd="))))
+      .WillRepeatedly(Return(0));
+  EXPECT_CALL(
+      *mock_exec_utils_,
+      DoExecAndReturnCode(AllOf(
+          Contains(Concatenate({"--boot-image=",
+              GetPrebuiltPrimaryBootImageDir(), "/boot.art:",
+              framework_dir_, "/boot-framework.art"})),
+          Contains(FlagContains("-Xbootclasspathimagefds:", FdOf(artifacts.ImagePath()))),
+          Contains(FlagContains("-Xbootclasspathvdexfds:", FdOf(artifacts.VdexPath()))),
+          Contains(FlagContains("-Xbootclasspathoatfds:", FdOf(artifacts.OatPath()))))))
+      .Times(odrefresh_->AllSystemServerJars().size())
+      .WillRepeatedly(Return(0));
+  EXPECT_EQ(
+      odrefresh_->Compile(*metrics_,
+                          CompilationOptions{
+                            .system_server_jars_to_compile = odrefresh_->AllSystemServerJars(),
+                          }),
+      ExitCode::kCompilationSuccess);
 }
 
 }  // namespace odrefresh
diff --git a/tools/buildbot-build.sh b/tools/buildbot-build.sh
index 900a858..b89efa2 100755
--- a/tools/buildbot-build.sh
+++ b/tools/buildbot-build.sh
@@ -129,8 +129,6 @@
   # chroot environment. The *.libraries.txt targets are required by
   # the source linkerconfig but not included in the prebuilt one.
   make_command+=" linkerconfig conv_linker_config sanitizer.libraries.txt vndkcorevariant.libraries.txt"
-  # Additional dependency in /system
-  make_command+=" libbinder_ndk"
   # Additional targets needed for the chroot environment.
   make_command+=" event-log-tags"
   # Needed to extract prebuilt APEXes.