Revert "Refactor argument creation to be before the fork"

This reverts commit 62d218d4b1dc716cb8cb4a369ed679d56eede7a5.

Reason for revert: atest InstallDexMetadataHostTest

Change-Id: I6c640ac6dc54f0890e07448cf48893d298208a75
diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp
index 50a2412..90cadb4 100644
--- a/cmds/installd/dexopt.cpp
+++ b/cmds/installd/dexopt.cpp
@@ -201,53 +201,23 @@
     }
 }
 
-// ExecVHelper prepares and holds pointers to parsed command line arguments so that no allocations
-// need to be performed between the fork and exec.
-class ExecVHelper {
-  public:
-    // Store a placeholder for the binary name.
-    ExecVHelper() : args_(1u, std::string()) {}
-
-    void PrepareArgs(const std::string& bin) {
-        CHECK(!args_.empty());
-        CHECK(args_[0].empty());
-        args_[0] = bin;
-        // Write char* into array.
-        for (const std::string& arg : args_) {
-            argv_.push_back(arg.c_str());
-        }
-        argv_.push_back(nullptr);  // Add null terminator.
+// Automatically adds binary and null terminator arg.
+static inline void ExecVWithArgs(const char* bin, const std::vector<std::string>& args) {
+    std::vector<const char*> argv = {bin};
+    for (const std::string& arg : args) {
+        argv.push_back(arg.c_str());
     }
+    // Add null terminator.
+    argv.push_back(nullptr);
+    execv(bin, (char * const *)&argv[0]);
+}
 
-    [[ noreturn ]]
-    void Exec(int exit_code) {
-        execv(argv_[0], (char * const *)&argv_[0]);
-        PLOG(ERROR) << "execv(" << argv_[0] << ") failed";
-        exit(exit_code);
+static inline void AddArgIfNonEmpty(const std::string& arg, std::vector<std::string>* args) {
+    DCHECK(args != nullptr);
+    if (!arg.empty()) {
+        args->push_back(arg);
     }
-
-    // Add an arg if it's not empty.
-    void AddArg(const std::string& arg) {
-        if (!arg.empty()) {
-            args_.push_back(arg);
-        }
-    }
-
-    // Add a runtime arg if it's not empty.
-    void AddRuntimeArg(const std::string& arg) {
-        if (!arg.empty()) {
-            args_.push_back("--runtime-arg");
-            args_.push_back(arg);
-        }
-    }
-
-  protected:
-    // Holder arrays for backing arg storage.
-    std::vector<std::string> args_;
-
-    // Argument poiners.
-    std::vector<const char*> argv_;
-};
+}
 
 static std::string MapPropertyToArg(const std::string& property,
                                     const std::string& format,
@@ -259,220 +229,212 @@
   return "";
 }
 
-class RunDex2Oat : public ExecVHelper {
-  public:
-    RunDex2Oat(int zip_fd,
-               int oat_fd,
-               int input_vdex_fd,
-               int output_vdex_fd,
-               int image_fd,
-               const char* input_file_name,
-               const char* output_file_name,
-               int swap_fd,
-               const char* instruction_set,
-               const char* compiler_filter,
-               bool debuggable,
-               bool post_bootcomplete,
-               bool background_job_compile,
-               int profile_fd,
-               const char* class_loader_context,
-               int target_sdk_version,
-               bool enable_hidden_api_checks,
-               bool generate_compact_dex,
-               int dex_metadata_fd,
-               const char* compilation_reason) {
-        // Get the relative path to the input file.
-        const char* relative_input_file_name = get_location_from_path(input_file_name);
+[[ noreturn ]]
+static void run_dex2oat(int zip_fd, int oat_fd, int input_vdex_fd, int output_vdex_fd, int image_fd,
+        const char* input_file_name, const char* output_file_name, int swap_fd,
+        const char* instruction_set, const char* compiler_filter,
+        bool debuggable, bool post_bootcomplete, bool background_job_compile, int profile_fd,
+        const char* class_loader_context, int target_sdk_version, bool enable_hidden_api_checks,
+        bool generate_compact_dex, int dex_metadata_fd, const char* compilation_reason) {
+    // Get the relative path to the input file.
+    const char* relative_input_file_name = get_location_from_path(input_file_name);
 
-        std::string dex2oat_Xms_arg = MapPropertyToArg("dalvik.vm.dex2oat-Xms", "-Xms%s");
-        std::string dex2oat_Xmx_arg = MapPropertyToArg("dalvik.vm.dex2oat-Xmx", "-Xmx%s");
+    std::string dex2oat_Xms_arg = MapPropertyToArg("dalvik.vm.dex2oat-Xms", "-Xms%s");
+    std::string dex2oat_Xmx_arg = MapPropertyToArg("dalvik.vm.dex2oat-Xmx", "-Xmx%s");
 
-        const char* threads_property = post_bootcomplete
-                ? "dalvik.vm.dex2oat-threads"
-                : "dalvik.vm.boot-dex2oat-threads";
-        std::string dex2oat_threads_arg = MapPropertyToArg(threads_property, "-j%s");
+    const char* threads_property = post_bootcomplete
+            ? "dalvik.vm.dex2oat-threads"
+            : "dalvik.vm.boot-dex2oat-threads";
+    std::string dex2oat_threads_arg = MapPropertyToArg(threads_property, "-j%s");
 
-        const std::string dex2oat_isa_features_key =
-                StringPrintf("dalvik.vm.isa.%s.features", instruction_set);
-        std::string instruction_set_features_arg =
-            MapPropertyToArg(dex2oat_isa_features_key, "--instruction-set-features=%s");
+    const std::string dex2oat_isa_features_key =
+            StringPrintf("dalvik.vm.isa.%s.features", instruction_set);
+    std::string instruction_set_features_arg =
+        MapPropertyToArg(dex2oat_isa_features_key, "--instruction-set-features=%s");
 
-        const std::string dex2oat_isa_variant_key =
-                StringPrintf("dalvik.vm.isa.%s.variant", instruction_set);
-        std::string instruction_set_variant_arg =
-            MapPropertyToArg(dex2oat_isa_variant_key, "--instruction-set-variant=%s");
+    const std::string dex2oat_isa_variant_key =
+            StringPrintf("dalvik.vm.isa.%s.variant", instruction_set);
+    std::string instruction_set_variant_arg =
+        MapPropertyToArg(dex2oat_isa_variant_key, "--instruction-set-variant=%s");
 
-        const char* dex2oat_norelocation = "-Xnorelocate";
+    const char *dex2oat_norelocation = "-Xnorelocate";
 
-        const std::string dex2oat_flags = GetProperty("dalvik.vm.dex2oat-flags", "");
-        std::vector<std::string> dex2oat_flags_args = SplitBySpaces(dex2oat_flags);
-        ALOGV("dalvik.vm.dex2oat-flags=%s\n", dex2oat_flags.c_str());
+    const std::string dex2oat_flags = GetProperty("dalvik.vm.dex2oat-flags", "");
+    std::vector<std::string> dex2oat_flags_args = SplitBySpaces(dex2oat_flags);
+    ALOGV("dalvik.vm.dex2oat-flags=%s\n", dex2oat_flags.c_str());
 
-        // If we are booting without the real /data, don't spend time compiling.
-        std::string vold_decrypt = GetProperty("vold.decrypt", "");
-        bool skip_compilation = vold_decrypt == "trigger_restart_min_framework" ||
-                                vold_decrypt == "1";
+    // If we are booting without the real /data, don't spend time compiling.
+    std::string vold_decrypt = GetProperty("vold.decrypt", "");
+    bool skip_compilation = vold_decrypt == "trigger_restart_min_framework" ||
+                            vold_decrypt == "1";
 
-        const std::string resolve_startup_string_arg  =
-                MapPropertyToArg("dalvik.vm.dex2oat-resolve-startup-strings",
-                                 "--resolve-startup-const-strings=%s");
-        const bool generate_debug_info = GetBoolProperty("debug.generate-debug-info", false);
+    const std::string resolve_startup_string_arg  =
+            MapPropertyToArg("dalvik.vm.dex2oat-resolve-startup-strings",
+                             "--resolve-startup-const-strings=%s");
+    const bool generate_debug_info = GetBoolProperty("debug.generate-debug-info", false);
 
-        std::string image_format_arg;
-        if (image_fd >= 0) {
-            image_format_arg = MapPropertyToArg("dalvik.vm.appimageformat", "--image-format=%s");
-        }
-
-        std::string dex2oat_large_app_threshold_arg =
-            MapPropertyToArg("dalvik.vm.dex2oat-very-large", "--very-large-app-threshold=%s");
-
-        // If the runtime was requested to use libartd.so, we'll run dex2oatd, otherwise dex2oat.
-        const char* dex2oat_bin = "/system/bin/dex2oat";
-        constexpr const char* kDex2oatDebugPath = "/system/bin/dex2oatd";
-        // Do not use dex2oatd for release candidates (give dex2oat more soak time).
-        bool is_release = android::base::GetProperty("ro.build.version.codename", "") == "REL";
-        if (is_debug_runtime() ||
-                (background_job_compile && is_debuggable_build() && !is_release)) {
-            if (access(kDex2oatDebugPath, X_OK) == 0) {
-                dex2oat_bin = kDex2oatDebugPath;
-            }
-        }
-
-        bool generate_minidebug_info = kEnableMinidebugInfo &&
-                GetBoolProperty(kMinidebugInfoSystemProperty, kMinidebugInfoSystemPropertyDefault);
-
-        // clang FORTIFY doesn't let us use strlen in constant array bounds, so we
-        // use arraysize instead.
-        std::string zip_fd_arg = StringPrintf("--zip-fd=%d", zip_fd);
-        std::string zip_location_arg = StringPrintf("--zip-location=%s", relative_input_file_name);
-        std::string input_vdex_fd_arg = StringPrintf("--input-vdex-fd=%d", input_vdex_fd);
-        std::string output_vdex_fd_arg = StringPrintf("--output-vdex-fd=%d", output_vdex_fd);
-        std::string oat_fd_arg = StringPrintf("--oat-fd=%d", oat_fd);
-        std::string oat_location_arg = StringPrintf("--oat-location=%s", output_file_name);
-        std::string instruction_set_arg = StringPrintf("--instruction-set=%s", instruction_set);
-        std::string dex2oat_compiler_filter_arg;
-        std::string dex2oat_swap_fd;
-        std::string dex2oat_image_fd;
-        std::string target_sdk_version_arg;
-        if (target_sdk_version != 0) {
-            StringPrintf("-Xtarget-sdk-version:%d", target_sdk_version);
-        }
-        std::string class_loader_context_arg;
-        if (class_loader_context != nullptr) {
-            class_loader_context_arg = StringPrintf("--class-loader-context=%s",
-                                                    class_loader_context);
-        }
-
-        if (swap_fd >= 0) {
-            dex2oat_swap_fd = StringPrintf("--swap-fd=%d", swap_fd);
-        }
-        if (image_fd >= 0) {
-            dex2oat_image_fd = StringPrintf("--app-image-fd=%d", image_fd);
-        }
-
-        // Compute compiler filter.
-        bool have_dex2oat_relocation_skip_flag = false;
-        if (skip_compilation) {
-            dex2oat_compiler_filter_arg = "--compiler-filter=extract";
-            have_dex2oat_relocation_skip_flag = true;
-        } else if (compiler_filter != nullptr) {
-            dex2oat_compiler_filter_arg = StringPrintf("--compiler-filter=%s", compiler_filter);
-        }
-
-        if (dex2oat_compiler_filter_arg.empty()) {
-            dex2oat_compiler_filter_arg = MapPropertyToArg("dalvik.vm.dex2oat-filter",
-                                                           "--compiler-filter=%s");
-        }
-
-        // Check whether all apps should be compiled debuggable.
-        if (!debuggable) {
-            debuggable = GetProperty("dalvik.vm.always_debuggable", "") == "1";
-        }
-        std::string profile_arg;
-        if (profile_fd != -1) {
-            profile_arg = StringPrintf("--profile-file-fd=%d", profile_fd);
-        }
-
-        // Get the directory of the apk to pass as a base classpath directory.
-        std::string base_dir;
-        std::string apk_dir(input_file_name);
-        unsigned long dir_index = apk_dir.rfind('/');
-        bool has_base_dir = dir_index != std::string::npos;
-        if (has_base_dir) {
-            apk_dir = apk_dir.substr(0, dir_index);
-            base_dir = StringPrintf("--classpath-dir=%s", apk_dir.c_str());
-        }
-
-        std::string dex_metadata_fd_arg = "--dm-fd=" + std::to_string(dex_metadata_fd);
-
-        std::string compilation_reason_arg = compilation_reason == nullptr
-                ? ""
-                : std::string("--compilation-reason=") + compilation_reason;
-
-        ALOGV("Running %s in=%s out=%s\n", dex2oat_bin, relative_input_file_name, output_file_name);
-
-        // Disable cdex if update input vdex is true since this combination of options is not
-        // supported.
-        const bool disable_cdex = !generate_compact_dex || (input_vdex_fd == output_vdex_fd);
-
-        AddArg(zip_fd_arg);
-        AddArg(zip_location_arg);
-        AddArg(input_vdex_fd_arg);
-        AddArg(output_vdex_fd_arg);
-        AddArg(oat_fd_arg);
-        AddArg(oat_location_arg);
-        AddArg(instruction_set_arg);
-
-        AddArg(instruction_set_variant_arg);
-        AddArg(instruction_set_features_arg);
-
-        AddRuntimeArg(dex2oat_Xms_arg);
-        AddRuntimeArg(dex2oat_Xmx_arg);
-
-        AddArg(resolve_startup_string_arg);
-        AddArg(dex2oat_compiler_filter_arg);
-        AddArg(dex2oat_threads_arg);
-        AddArg(dex2oat_swap_fd);
-        AddArg(dex2oat_image_fd);
-
-        if (generate_debug_info) {
-            AddArg("--generate-debug-info");
-        }
-        if (debuggable) {
-            AddArg("--debuggable");
-        }
-        AddArg(image_format_arg);
-        AddArg(dex2oat_large_app_threshold_arg);
-
-        if (have_dex2oat_relocation_skip_flag) {
-            AddRuntimeArg(dex2oat_norelocation);
-        }
-        AddArg(profile_arg);
-        AddArg(base_dir);
-        AddArg(class_loader_context_arg);
-        if (generate_minidebug_info) {
-            AddArg(kMinidebugDex2oatFlag);
-        }
-        if (disable_cdex) {
-            AddArg(kDisableCompactDexFlag);
-        }
-        AddArg(target_sdk_version_arg);
-        if (enable_hidden_api_checks) {
-            AddRuntimeArg("-Xhidden-api-checks");
-        }
-
-        if (dex_metadata_fd > -1) {
-            AddArg(dex_metadata_fd_arg);
-        }
-
-        AddArg(compilation_reason_arg);
-
-        // Do not add args after dex2oat_flags, they should override others for debugging.
-        args_.insert(args_.end(), dex2oat_flags_args.begin(), dex2oat_flags_args.end());
-
-        PrepareArgs(dex2oat_bin);
+    std::string image_format_arg;
+    if (image_fd >= 0) {
+        image_format_arg = MapPropertyToArg("dalvik.vm.appimageformat", "--image-format=%s");
     }
-};
+
+    std::string dex2oat_large_app_threshold_arg =
+        MapPropertyToArg("dalvik.vm.dex2oat-very-large", "--very-large-app-threshold=%s");
+
+    // If the runtime was requested to use libartd.so, we'll run dex2oatd, otherwise dex2oat.
+    const char* dex2oat_bin = "/system/bin/dex2oat";
+    constexpr const char* kDex2oatDebugPath = "/system/bin/dex2oatd";
+    // Do not use dex2oatd for release candidates (give dex2oat more soak time).
+    bool is_release = android::base::GetProperty("ro.build.version.codename", "") == "REL";
+    if (is_debug_runtime() || (background_job_compile && is_debuggable_build() && !is_release)) {
+        if (access(kDex2oatDebugPath, X_OK) == 0) {
+            dex2oat_bin = kDex2oatDebugPath;
+        }
+    }
+
+    bool generate_minidebug_info = kEnableMinidebugInfo &&
+            android::base::GetBoolProperty(kMinidebugInfoSystemProperty,
+                                           kMinidebugInfoSystemPropertyDefault);
+
+    // clang FORTIFY doesn't let us use strlen in constant array bounds, so we
+    // use arraysize instead.
+    std::string zip_fd_arg = StringPrintf("--zip-fd=%d", zip_fd);
+    std::string zip_location_arg = StringPrintf("--zip-location=%s", relative_input_file_name);
+    std::string input_vdex_fd_arg = StringPrintf("--input-vdex-fd=%d", input_vdex_fd);
+    std::string output_vdex_fd_arg = StringPrintf("--output-vdex-fd=%d", output_vdex_fd);
+    std::string oat_fd_arg = StringPrintf("--oat-fd=%d", oat_fd);
+    std::string oat_location_arg = StringPrintf("--oat-location=%s", output_file_name);
+    std::string instruction_set_arg = StringPrintf("--instruction-set=%s", instruction_set);
+    std::string dex2oat_compiler_filter_arg;
+    std::string dex2oat_swap_fd;
+    std::string dex2oat_image_fd;
+    std::string target_sdk_version_arg;
+    if (target_sdk_version != 0) {
+        StringPrintf("-Xtarget-sdk-version:%d", target_sdk_version);
+    }
+    std::string class_loader_context_arg;
+    if (class_loader_context != nullptr) {
+        class_loader_context_arg = StringPrintf("--class-loader-context=%s", class_loader_context);
+    }
+
+    if (swap_fd >= 0) {
+        dex2oat_swap_fd = StringPrintf("--swap-fd=%d", swap_fd);
+    }
+    if (image_fd >= 0) {
+        dex2oat_image_fd = StringPrintf("--app-image-fd=%d", image_fd);
+    }
+
+    // Compute compiler filter.
+    bool have_dex2oat_relocation_skip_flag = false;
+    if (skip_compilation) {
+        dex2oat_compiler_filter_arg = "--compiler-filter=extract";
+        have_dex2oat_relocation_skip_flag = true;
+    } else if (compiler_filter != nullptr) {
+        dex2oat_compiler_filter_arg = StringPrintf("--compiler-filter=%s", compiler_filter);
+    }
+
+    if (dex2oat_compiler_filter_arg.empty()) {
+        dex2oat_compiler_filter_arg = MapPropertyToArg("dalvik.vm.dex2oat-filter",
+                                                       "--compiler-filter=%s");
+    }
+
+    // Check whether all apps should be compiled debuggable.
+    if (!debuggable) {
+        debuggable = GetProperty("dalvik.vm.always_debuggable", "") == "1";
+    }
+    std::string profile_arg;
+    if (profile_fd != -1) {
+        profile_arg = StringPrintf("--profile-file-fd=%d", profile_fd);
+    }
+
+    // Get the directory of the apk to pass as a base classpath directory.
+    std::string base_dir;
+    std::string apk_dir(input_file_name);
+    unsigned long dir_index = apk_dir.rfind('/');
+    bool has_base_dir = dir_index != std::string::npos;
+    if (has_base_dir) {
+        apk_dir = apk_dir.substr(0, dir_index);
+        base_dir = StringPrintf("--classpath-dir=%s", apk_dir.c_str());
+    }
+
+    std::string dex_metadata_fd_arg = "--dm-fd=" + std::to_string(dex_metadata_fd);
+
+    std::string compilation_reason_arg = compilation_reason == nullptr
+            ? ""
+            : std::string("--compilation-reason=") + compilation_reason;
+
+    ALOGV("Running %s in=%s out=%s\n", dex2oat_bin, relative_input_file_name, output_file_name);
+
+    // Disable cdex if update input vdex is true since this combination of options is not
+    // supported.
+    const bool disable_cdex = !generate_compact_dex || (input_vdex_fd == output_vdex_fd);
+
+    std::vector<std::string> args = {
+        zip_fd_arg,
+        zip_location_arg,
+        input_vdex_fd_arg,
+        output_vdex_fd_arg,
+        oat_fd_arg,
+        oat_location_arg,
+        instruction_set_arg,
+    };
+    auto add_runtime_arg = [&](const std::string& arg) {
+        args.push_back("--runtime-arg");
+        args.push_back(arg);
+    };
+
+    AddArgIfNonEmpty(instruction_set_variant_arg, &args);
+    AddArgIfNonEmpty(instruction_set_features_arg, &args);
+    if (!dex2oat_Xms_arg.empty()) {
+        add_runtime_arg(dex2oat_Xms_arg);
+    }
+    if (!dex2oat_Xmx_arg.empty()) {
+        add_runtime_arg(dex2oat_Xmx_arg);
+    }
+    AddArgIfNonEmpty(resolve_startup_string_arg, &args);
+    AddArgIfNonEmpty(dex2oat_compiler_filter_arg, &args);
+    AddArgIfNonEmpty(dex2oat_threads_arg, &args);
+    AddArgIfNonEmpty(dex2oat_swap_fd, &args);
+    AddArgIfNonEmpty(dex2oat_image_fd, &args);
+
+    if (generate_debug_info) {
+        args.push_back("--generate-debug-info");
+    }
+    if (debuggable) {
+        args.push_back("--debuggable");
+    }
+    AddArgIfNonEmpty(image_format_arg, &args);
+    AddArgIfNonEmpty(dex2oat_large_app_threshold_arg, &args);
+    args.insert(args.end(), dex2oat_flags_args.begin(), dex2oat_flags_args.end());
+    if (have_dex2oat_relocation_skip_flag) {
+        add_runtime_arg(dex2oat_norelocation);
+    }
+    AddArgIfNonEmpty(profile_arg, &args);
+    AddArgIfNonEmpty(base_dir, &args);
+    AddArgIfNonEmpty(class_loader_context_arg, &args);
+    if (generate_minidebug_info) {
+        args.push_back(kMinidebugDex2oatFlag);
+    }
+    if (disable_cdex) {
+        args.push_back(kDisableCompactDexFlag);
+    }
+    AddArgIfNonEmpty(target_sdk_version_arg, &args);
+    if (enable_hidden_api_checks) {
+        add_runtime_arg("-Xhidden-api-checks");
+    }
+
+    if (dex_metadata_fd > -1) {
+        args.push_back(dex_metadata_fd_arg);
+    }
+
+    AddArgIfNonEmpty(compilation_reason_arg, &args);
+
+    // Do not add after dex2oat_flags, they should override others for debugging.
+
+    ExecVWithArgs(dex2oat_bin, args);
+    PLOG(ERROR) << "execv(" << dex2oat_bin << ") failed";
+    exit(DexoptReturnCodes::kDex2oatExec);
+}
 
 /*
  * Whether dexopt should use a swap file when compiling an APK.
@@ -648,85 +610,74 @@
 static constexpr int PROFMAN_BIN_RETURN_CODE_ERROR_IO = 3;
 static constexpr int PROFMAN_BIN_RETURN_CODE_ERROR_LOCKING = 4;
 
-class RunProfman : public ExecVHelper {
-  public:
-   void SetupArgs(const std::vector<unique_fd>& profile_fds,
-                  const unique_fd& reference_profile_fd,
-                  const std::vector<unique_fd>& apk_fds,
-                  const std::vector<std::string>& dex_locations,
-                  bool copy_and_update) {
-        const char* profman_bin =
-                is_debug_runtime() ? "/system/bin/profmand" : "/system/bin/profman";
+[[ noreturn ]]
+static void run_profman(const std::vector<unique_fd>& profile_fds,
+                        const unique_fd& reference_profile_fd,
+                        const std::vector<unique_fd>* apk_fds,
+                        const std::vector<std::string>* dex_locations,
+                        bool copy_and_update) {
+    const char* profman_bin = is_debug_runtime() ? "/system/bin/profmand" : "/system/bin/profman";
 
-        if (copy_and_update) {
-            CHECK_EQ(1u, profile_fds.size());
-            CHECK_EQ(1u, apk_fds.size());
-        }
-        if (reference_profile_fd != -1) {
-            AddArg("--reference-profile-file-fd=" + std::to_string(reference_profile_fd.get()));
-        }
+    if (copy_and_update) {
+        CHECK_EQ(1u, profile_fds.size());
+        CHECK(apk_fds != nullptr);
+        CHECK_EQ(1u, apk_fds->size());
+    }
+    std::vector<std::string> args;
+    args.push_back("--reference-profile-file-fd=" + std::to_string(reference_profile_fd.get()));
 
-        for (const unique_fd& fd : profile_fds) {
-            AddArg("--profile-file-fd=" + std::to_string(fd.get()));
-        }
-
-        for (const unique_fd& fd : apk_fds) {
-            AddArg("--apk-fd=" + std::to_string(fd.get()));
-        }
-
-        for (const std::string& dex_location : dex_locations) {
-            AddArg("--dex-location=" + dex_location);
-        }
-
-        if (copy_and_update) {
-            AddArg("--copy-and-update-profile-key");
-        }
-
-        // Do not add after dex2oat_flags, they should override others for debugging.
-        PrepareArgs(profman_bin);
+    for (const unique_fd& fd : profile_fds) {
+        args.push_back("--profile-file-fd=" + std::to_string(fd.get()));
     }
 
-    void SetupMerge(const std::vector<unique_fd>& profiles_fd,
-                    const unique_fd& reference_profile_fd,
-                    const std::vector<unique_fd>& apk_fds = std::vector<unique_fd>(),
-                    const std::vector<std::string>& dex_locations = std::vector<std::string>()) {
-        SetupArgs(profiles_fd,
-                    reference_profile_fd,
-                    apk_fds,
-                    dex_locations,
-                    /*copy_and_update=*/false);
+    if (apk_fds != nullptr) {
+        for (const unique_fd& fd : *apk_fds) {
+            args.push_back("--apk-fd=" + std::to_string(fd.get()));
+        }
     }
 
-    void SetupCopyAndUpdate(unique_fd&& profile_fd,
-                            unique_fd&& reference_profile_fd,
-                            unique_fd&& apk_fd,
-                            const std::string& dex_location) {
-        std::vector<unique_fd> profiles_fd;
-        profiles_fd.push_back(std::move(profile_fd));
-        std::vector<unique_fd> apk_fds;
-        profiles_fd.push_back(std::move(apk_fd));
-        std::vector<std::string> dex_locations = {dex_location};
-        SetupArgs(profiles_fd, reference_profile_fd, apk_fds, dex_locations,
-                  /*copy_and_update=*/true);
+    std::vector<std::string> dex_location_args;
+    if (dex_locations != nullptr) {
+        for (const std::string& dex_location : *dex_locations) {
+            args.push_back("--dex-location=" + dex_location);
+        }
     }
 
-    void SetupDump(const std::vector<unique_fd>& profiles_fd,
-                   const unique_fd& reference_profile_fd,
-                   const std::vector<std::string>& dex_locations,
-                   const std::vector<unique_fd>& apk_fds,
-                   const unique_fd& output_fd) {
-        AddArg("--dump-only");
-        AddArg(StringPrintf("--dump-output-to-fd=%d", output_fd.get()));
-        SetupArgs(profiles_fd, reference_profile_fd, apk_fds, dex_locations,
-                  /*copy_and_update=*/false);
+    if (copy_and_update) {
+        args.push_back("--copy-and-update-profile-key");
     }
 
-    void Exec() {
-        ExecVHelper::Exec(DexoptReturnCodes::kProfmanExec);
-    }
-};
+    // Do not add after dex2oat_flags, they should override others for debugging.
 
+    ExecVWithArgs(profman_bin, args);
+    PLOG(ERROR) << "execv(" << profman_bin << ") failed";
+    exit(DexoptReturnCodes::kProfmanExec);   /* only get here on exec failure */
+}
 
+[[ noreturn ]]
+static void run_profman_merge(const std::vector<unique_fd>& profiles_fd,
+                              const unique_fd& reference_profile_fd,
+                              const std::vector<unique_fd>* apk_fds = nullptr,
+                              const std::vector<std::string>* dex_locations = nullptr) {
+    run_profman(profiles_fd, reference_profile_fd, apk_fds, dex_locations,
+            /*copy_and_update*/false);
+}
+
+[[ noreturn ]]
+static void run_profman_copy_and_update(unique_fd&& profile_fd,
+                                        unique_fd&& reference_profile_fd,
+                                        unique_fd&& apk_fd,
+                                        const std::string& dex_location) {
+    std::vector<unique_fd> profiles_fd;
+    profiles_fd.push_back(std::move(profile_fd));
+    std::vector<unique_fd> apk_fds;
+    apk_fds.push_back(std::move(apk_fd));
+    std::vector<std::string> dex_locations;
+    dex_locations.push_back(dex_location);
+
+    run_profman(profiles_fd, reference_profile_fd, &apk_fds, &dex_locations,
+            /*copy_and_update*/true);
+}
 
 // Decides if profile guided compilation is needed or not based on existing profiles.
 // The location is the package name for primary apks or the dex path for secondary dex files.
@@ -746,13 +697,11 @@
         return false;
     }
 
-    RunProfman profman_merge;
-    profman_merge.SetupMerge(profiles_fd, reference_profile_fd);
     pid_t pid = fork();
     if (pid == 0) {
         /* child -- drop privileges before continuing */
         drop_capabilities(uid);
-        profman_merge.Exec();
+        run_profman_merge(profiles_fd, reference_profile_fd);
     }
     /* parent */
     int return_code = wait_child(pid);
@@ -825,6 +774,35 @@
     return analyze_profiles(uid, package_name, profile_name, /*is_secondary_dex*/false);
 }
 
+[[ noreturn ]]
+static void run_profman_dump(const std::vector<unique_fd>& profile_fds,
+                             const unique_fd& reference_profile_fd,
+                             const std::vector<std::string>& dex_locations,
+                             const std::vector<unique_fd>& apk_fds,
+                             const unique_fd& output_fd) {
+    std::vector<std::string> profman_args;
+    static const char* PROFMAN_BIN = "/system/bin/profman";
+    profman_args.push_back("--dump-only");
+    profman_args.push_back(StringPrintf("--dump-output-to-fd=%d", output_fd.get()));
+    if (reference_profile_fd != -1) {
+        profman_args.push_back(StringPrintf("--reference-profile-file-fd=%d",
+                                            reference_profile_fd.get()));
+    }
+    for (size_t i = 0; i < profile_fds.size(); i++) {
+        profman_args.push_back(StringPrintf("--profile-file-fd=%d", profile_fds[i].get()));
+    }
+    for (const std::string& dex_location : dex_locations) {
+        profman_args.push_back(StringPrintf("--dex-location=%s", dex_location.c_str()));
+    }
+    for (size_t i = 0; i < apk_fds.size(); i++) {
+        profman_args.push_back(StringPrintf("--apk-fd=%d", apk_fds[i].get()));
+    }
+
+    ExecVWithArgs(PROFMAN_BIN, profman_args);
+    PLOG(ERROR) << "execv(" << PROFMAN_BIN << ") failed";
+    exit(DexoptReturnCodes::kProfmanExec);   /* only get here on exec failure */
+}
+
 bool dump_profiles(int32_t uid, const std::string& pkgname, const std::string& profile_name,
         const std::string& code_path) {
     std::vector<unique_fd> profile_fds;
@@ -861,13 +839,12 @@
     apk_fds.push_back(std::move(apk_fd));
 
 
-    RunProfman profman_dump;
-    profman_dump.SetupDump(profile_fds, reference_profile_fd, dex_locations, apk_fds, output_fd);
     pid_t pid = fork();
     if (pid == 0) {
         /* child -- drop privileges before continuing */
         drop_capabilities(uid);
-        profman_dump.Exec();
+        run_profman_dump(profile_fds, reference_profile_fd, dex_locations,
+                         apk_fds, output_fd);
     }
     /* parent */
     int return_code = wait_child(pid);
@@ -1439,60 +1416,55 @@
 // The analyzer will check if the dex_file needs to be (re)compiled to match the compiler_filter.
 // If this is for a profile guided compilation, profile_was_updated will tell whether or not
 // the profile has changed.
-class RunDexoptAnalyzer : public ExecVHelper {
- public:
-    RunDexoptAnalyzer(const std::string& dex_file,
-                    int vdex_fd,
-                    int oat_fd,
-                    int zip_fd,
-                    const std::string& instruction_set,
-                    const std::string& compiler_filter,
-                    bool profile_was_updated,
-                    bool downgrade,
-                    const char* class_loader_context) {
-        CHECK_GE(zip_fd, 0);
-        const char* dexoptanalyzer_bin =
-                is_debug_runtime()
-                        ? "/system/bin/dexoptanalyzerd"
-                        : "/system/bin/dexoptanalyzer";
+static void exec_dexoptanalyzer(const std::string& dex_file, int vdex_fd, int oat_fd,
+        int zip_fd, const std::string& instruction_set, const std::string& compiler_filter,
+        bool profile_was_updated, bool downgrade,
+        const char* class_loader_context) {
+    CHECK_GE(zip_fd, 0);
+    const char* dexoptanalyzer_bin =
+            is_debug_runtime()
+                    ? "/system/bin/dexoptanalyzerd"
+                    : "/system/bin/dexoptanalyzer";
 
-        std::string dex_file_arg = "--dex-file=" + dex_file;
-        std::string oat_fd_arg = "--oat-fd=" + std::to_string(oat_fd);
-        std::string vdex_fd_arg = "--vdex-fd=" + std::to_string(vdex_fd);
-        std::string zip_fd_arg = "--zip-fd=" + std::to_string(zip_fd);
-        std::string isa_arg = "--isa=" + instruction_set;
-        std::string compiler_filter_arg = "--compiler-filter=" + compiler_filter;
-        const char* assume_profile_changed = "--assume-profile-changed";
-        const char* downgrade_flag = "--downgrade";
-        std::string class_loader_context_arg = "--class-loader-context=";
-        if (class_loader_context != nullptr) {
-            class_loader_context_arg += class_loader_context;
-        }
-
-        // program name, dex file, isa, filter
-        AddArg(dex_file_arg);
-        AddArg(isa_arg);
-        AddArg(compiler_filter_arg);
-        if (oat_fd >= 0) {
-            AddArg(oat_fd_arg);
-        }
-        if (vdex_fd >= 0) {
-            AddArg(vdex_fd_arg);
-        }
-        AddArg(zip_fd_arg.c_str());
-        if (profile_was_updated) {
-            AddArg(assume_profile_changed);
-        }
-        if (downgrade) {
-            AddArg(downgrade_flag);
-        }
-        if (class_loader_context != nullptr) {
-            AddArg(class_loader_context_arg.c_str());
-        }
-
-        PrepareArgs(dexoptanalyzer_bin);
+    std::string dex_file_arg = "--dex-file=" + dex_file;
+    std::string oat_fd_arg = "--oat-fd=" + std::to_string(oat_fd);
+    std::string vdex_fd_arg = "--vdex-fd=" + std::to_string(vdex_fd);
+    std::string zip_fd_arg = "--zip-fd=" + std::to_string(zip_fd);
+    std::string isa_arg = "--isa=" + instruction_set;
+    std::string compiler_filter_arg = "--compiler-filter=" + compiler_filter;
+    const char* assume_profile_changed = "--assume-profile-changed";
+    const char* downgrade_flag = "--downgrade";
+    std::string class_loader_context_arg = "--class-loader-context=";
+    if (class_loader_context != nullptr) {
+        class_loader_context_arg += class_loader_context;
     }
-};
+
+    // program name, dex file, isa, filter
+    std::vector<std::string> args = {
+      dex_file_arg,
+      isa_arg,
+      compiler_filter_arg,
+    };
+    if (oat_fd >= 0) {
+        args.push_back(oat_fd_arg);
+    }
+    if (vdex_fd >= 0) {
+        args.push_back(vdex_fd_arg);
+    }
+    args.push_back(zip_fd_arg.c_str());
+    if (profile_was_updated) {
+        args.push_back(assume_profile_changed);
+    }
+    if (downgrade) {
+        args.push_back(downgrade_flag);
+    }
+    if (class_loader_context != nullptr) {
+        args.push_back(class_loader_context_arg.c_str());
+    }
+
+    ExecVWithArgs(dexoptanalyzer_bin, args);
+    ALOGE("execv(%s) failed: %s\n", dexoptanalyzer_bin, strerror(errno));
+}
 
 // Prepares the oat dir for the secondary dex files.
 static bool prepare_secondary_dex_oat_dir(const std::string& dex_path, int uid,
@@ -1744,17 +1716,16 @@
                 /*is_secondary_dex*/true);
 
         // Run dexoptanalyzer to get dexopt_needed code. This is not expected to return.
-        // Note that we do not do it before the fork since opening the files is required to happen
-        // after forking.
-        RunDexoptAnalyzer run_dexopt_analyzer(dex_path,
-                                              vdex_file_fd.get(),
-                                              oat_file_fd.get(),
-                                              zip_fd.get(),
-                                              instruction_set,
-                                              compiler_filter, profile_was_updated,
-                                              downgrade,
-                                              class_loader_context);
-        run_dexopt_analyzer.Exec(kSecondaryDexDexoptAnalyzerSkippedFailExec);
+        exec_dexoptanalyzer(dex_path,
+                            vdex_file_fd.get(),
+                            oat_file_fd.get(),
+                            zip_fd.get(),
+                            instruction_set,
+                            compiler_filter, profile_was_updated,
+                            downgrade,
+                            class_loader_context);
+        PLOG(ERROR) << "Failed to exec dexoptanalyzer";
+        _exit(kSecondaryDexDexoptAnalyzerSkippedFailExec);
     }
 
     /* parent */
@@ -1923,27 +1894,6 @@
 
     LOG(VERBOSE) << "DexInv: --- BEGIN '" << dex_path << "' ---";
 
-    RunDex2Oat runner(input_fd.get(),
-                      out_oat_fd.get(),
-                      in_vdex_fd.get(),
-                      out_vdex_fd.get(),
-                      image_fd.get(),
-                      dex_path,
-                      out_oat_path,
-                      swap_fd.get(),
-                      instruction_set,
-                      compiler_filter,
-                      debuggable,
-                      boot_complete,
-                      background_job_compile,
-                      reference_profile_fd.get(),
-                      class_loader_context,
-                      target_sdk_version,
-                      enable_hidden_api_checks,
-                      generate_compact_dex,
-                      dex_metadata_fd.get(),
-                      compilation_reason);
-
     pid_t pid = fork();
     if (pid == 0) {
         /* child -- drop privileges before continuing */
@@ -1955,7 +1905,26 @@
             _exit(DexoptReturnCodes::kFlock);
         }
 
-        runner.Exec(DexoptReturnCodes::kDex2oatExec);
+        run_dex2oat(input_fd.get(),
+                    out_oat_fd.get(),
+                    in_vdex_fd.get(),
+                    out_vdex_fd.get(),
+                    image_fd.get(),
+                    dex_path,
+                    out_oat_path,
+                    swap_fd.get(),
+                    instruction_set,
+                    compiler_filter,
+                    debuggable,
+                    boot_complete,
+                    background_job_compile,
+                    reference_profile_fd.get(),
+                    class_loader_context,
+                    target_sdk_version,
+                    enable_hidden_api_checks,
+                    generate_compact_dex,
+                    dex_metadata_fd.get(),
+                    compilation_reason);
     } else {
         int res = wait_child(pid);
         if (res == 0) {
@@ -2519,13 +2488,11 @@
         return false;
     }
 
-    RunProfman args;
-    args.SetupMerge(profiles_fd, snapshot_fd, apk_fds, dex_locations);
     pid_t pid = fork();
     if (pid == 0) {
         /* child -- drop privileges before continuing */
         drop_capabilities(app_shared_gid);
-        args.Exec();
+        run_profman_merge(profiles_fd, snapshot_fd, &apk_fds, &dex_locations);
     }
 
     /* parent */
@@ -2605,8 +2572,6 @@
                 profiles_fd.push_back(std::move(fd));
             }
         }
-        RunProfman args;
-        args.SetupMerge(profiles_fd, snapshot_fd, apk_fds, dex_locations);
         pid_t pid = fork();
         if (pid == 0) {
             /* child -- drop privileges before continuing */
@@ -2614,7 +2579,7 @@
 
             // The introduction of new access flags into boot jars causes them to
             // fail dex file verification.
-            args.Exec();
+            run_profman_merge(profiles_fd, snapshot_fd, &apk_fds, &dex_locations);
         }
 
         /* parent */
@@ -2668,11 +2633,6 @@
         return false;
     }
 
-    RunProfman args;
-    args.SetupCopyAndUpdate(std::move(dex_metadata_fd),
-                            std::move(ref_profile_fd),
-                            std::move(apk_fd),
-                            code_path);
     pid_t pid = fork();
     if (pid == 0) {
         /* child -- drop privileges before continuing */
@@ -2680,7 +2640,10 @@
         drop_capabilities(app_shared_gid);
 
         // The copy and update takes ownership over the fds.
-        args.Exec();
+        run_profman_copy_and_update(std::move(dex_metadata_fd),
+                                    std::move(ref_profile_fd),
+                                    std::move(apk_fd),
+                                    code_path);
     }
 
     /* parent */