Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3163652b authored by Mathieu Chartier's avatar Mathieu Chartier
Browse files

Revert "Refactor argument creation to be before the fork"

This reverts commit 62d218d4.

Reason for revert: atest InstallDexMetadataHostTest

Change-Id: I6c640ac6dc54f0890e07448cf48893d298208a75
parent 62d218d4
Loading
Loading
Loading
Loading
+367 −404
Original line number Diff line number Diff line
@@ -201,54 +201,24 @@ static const char* get_location_from_path(const char* path) {
    }
}

// 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.
    }

    [[ noreturn ]]
    void Exec(int exit_code) {
        execv(argv_[0], (char * const *)&argv_[0]);
        PLOG(ERROR) << "execv(" << argv_[0] << ") failed";
        exit(exit_code);
    }

    // Add an arg if it's not empty.
    void AddArg(const std::string& arg) {
        if (!arg.empty()) {
            args_.push_back(arg);
// 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]);
}

    // Add a runtime arg if it's not empty.
    void AddRuntimeArg(const std::string& arg) {
static inline void AddArgIfNonEmpty(const std::string& arg, std::vector<std::string>* args) {
    DCHECK(args != nullptr);
    if (!arg.empty()) {
            args_.push_back("--runtime-arg");
            args_.push_back(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,
                                    const std::string& default_value = "") {
@@ -259,28 +229,13 @@ static std::string MapPropertyToArg(const std::string& property,
  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) {
[[ 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);

@@ -331,15 +286,15 @@ class RunDex2Oat : public ExecVHelper {
    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 (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);
            android::base::GetBoolProperty(kMinidebugInfoSystemProperty,
                                           kMinidebugInfoSystemPropertyDefault);

    // clang FORTIFY doesn't let us use strlen in constant array bounds, so we
    // use arraysize instead.
@@ -359,8 +314,7 @@ class RunDex2Oat : public ExecVHelper {
    }
    std::string class_loader_context_arg;
    if (class_loader_context != nullptr) {
            class_loader_context_arg = StringPrintf("--class-loader-context=%s",
                                                    class_loader_context);
        class_loader_context_arg = StringPrintf("--class-loader-context=%s", class_loader_context);
    }

    if (swap_fd >= 0) {
@@ -415,64 +369,72 @@ class RunDex2Oat : public ExecVHelper {
    // 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);
    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);
    };

        AddArg(resolve_startup_string_arg);
        AddArg(dex2oat_compiler_filter_arg);
        AddArg(dex2oat_threads_arg);
        AddArg(dex2oat_swap_fd);
        AddArg(dex2oat_image_fd);
    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) {
            AddArg("--generate-debug-info");
        args.push_back("--generate-debug-info");
    }
    if (debuggable) {
            AddArg("--debuggable");
        args.push_back("--debuggable");
    }
        AddArg(image_format_arg);
        AddArg(dex2oat_large_app_threshold_arg);

    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) {
            AddRuntimeArg(dex2oat_norelocation);
        add_runtime_arg(dex2oat_norelocation);
    }
        AddArg(profile_arg);
        AddArg(base_dir);
        AddArg(class_loader_context_arg);
    AddArgIfNonEmpty(profile_arg, &args);
    AddArgIfNonEmpty(base_dir, &args);
    AddArgIfNonEmpty(class_loader_context_arg, &args);
    if (generate_minidebug_info) {
            AddArg(kMinidebugDex2oatFlag);
        args.push_back(kMinidebugDex2oatFlag);
    }
    if (disable_cdex) {
            AddArg(kDisableCompactDexFlag);
        args.push_back(kDisableCompactDexFlag);
    }
        AddArg(target_sdk_version_arg);
    AddArgIfNonEmpty(target_sdk_version_arg, &args);
    if (enable_hidden_api_checks) {
            AddRuntimeArg("-Xhidden-api-checks");
        add_runtime_arg("-Xhidden-api-checks");
    }

    if (dex_metadata_fd > -1) {
            AddArg(dex_metadata_fd_arg);
        args.push_back(dex_metadata_fd_arg);
    }

        AddArg(compilation_reason_arg);
    AddArgIfNonEmpty(compilation_reason_arg, &args);

        // 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());
    // Do not add after dex2oat_flags, they should override others for debugging.

        PrepareArgs(dex2oat_bin);
    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_BAD_PROFILES = 2;
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,
[[ 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,
                        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";
    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()));
        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()));
        args.push_back("--profile-file-fd=" + std::to_string(fd.get()));
    }

        for (const unique_fd& fd : apk_fds) {
            AddArg("--apk-fd=" + std::to_string(fd.get()));
    if (apk_fds != nullptr) {
        for (const unique_fd& fd : *apk_fds) {
            args.push_back("--apk-fd=" + std::to_string(fd.get()));
        }
    }

        for (const std::string& dex_location : dex_locations) {
            AddArg("--dex-location=" + dex_location);
    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);
        }
    }

    if (copy_and_update) {
            AddArg("--copy-and-update-profile-key");
        args.push_back("--copy-and-update-profile-key");
    }

    // Do not add after dex2oat_flags, they should override others for debugging.
        PrepareArgs(profman_bin);

    ExecVWithArgs(profman_bin, args);
    PLOG(ERROR) << "execv(" << profman_bin << ") failed";
    exit(DexoptReturnCodes::kProfmanExec);   /* only get here on exec failure */
}

    void SetupMerge(const std::vector<unique_fd>& profiles_fd,
[[ 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 = 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);
                              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);
}

    void SetupCopyAndUpdate(unique_fd&& profile_fd,
[[ 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;
        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);
    }

    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);
    }
    apk_fds.push_back(std::move(apk_fd));
    std::vector<std::string> dex_locations;
    dex_locations.push_back(dex_location);

    void Exec() {
        ExecVHelper::Exec(DexoptReturnCodes::kProfmanExec);
    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 @@ static bool analyze_profiles(uid_t uid, const std::string& package_name,
        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 @@ bool analyze_primary_profiles(uid_t uid, const std::string& package_name,
    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 @@ bool dump_profiles(int32_t uid, const std::string& pkgname, const std::string& p
    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,16 +1416,9 @@ void update_out_oat_access_times(const char* apk_path, const char* out_oat_path)
// 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,
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 =
@@ -1470,29 +1440,31 @@ class RunDexoptAnalyzer : public ExecVHelper {
    }

    // program name, dex file, isa, filter
        AddArg(dex_file_arg);
        AddArg(isa_arg);
        AddArg(compiler_filter_arg);
    std::vector<std::string> args = {
      dex_file_arg,
      isa_arg,
      compiler_filter_arg,
    };
    if (oat_fd >= 0) {
            AddArg(oat_fd_arg);
        args.push_back(oat_fd_arg);
    }
    if (vdex_fd >= 0) {
            AddArg(vdex_fd_arg);
        args.push_back(vdex_fd_arg);
    }
        AddArg(zip_fd_arg.c_str());
    args.push_back(zip_fd_arg.c_str());
    if (profile_was_updated) {
            AddArg(assume_profile_changed);
        args.push_back(assume_profile_changed);
    }
    if (downgrade) {
            AddArg(downgrade_flag);
        args.push_back(downgrade_flag);
    }
    if (class_loader_context != nullptr) {
            AddArg(class_loader_context_arg.c_str());
        args.push_back(class_loader_context_arg.c_str());
    }

        PrepareArgs(dexoptanalyzer_bin);
    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,9 +1716,7 @@ static bool process_secondary_dex_dexopt(const std::string& dex_path, const char
                /*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,
        exec_dexoptanalyzer(dex_path,
                            vdex_file_fd.get(),
                            oat_file_fd.get(),
                            zip_fd.get(),
@@ -1754,7 +1724,8 @@ static bool process_secondary_dex_dexopt(const std::string& dex_path, const char
                            compiler_filter, profile_was_updated,
                            downgrade,
                            class_loader_context);
        run_dexopt_analyzer.Exec(kSecondaryDexDexoptAnalyzerSkippedFailExec);
        PLOG(ERROR) << "Failed to exec dexoptanalyzer";
        _exit(kSecondaryDexDexoptAnalyzerSkippedFailExec);
    }

    /* parent */
@@ -1923,7 +1894,18 @@ int dexopt(const char* dex_path, uid_t uid, const char* pkgname, const char* ins

    LOG(VERBOSE) << "DexInv: --- BEGIN '" << dex_path << "' ---";

    RunDex2Oat runner(input_fd.get(),
    pid_t pid = fork();
    if (pid == 0) {
        /* child -- drop privileges before continuing */
        drop_capabilities(uid);

        SetDex2OatScheduling(boot_complete);
        if (flock(out_oat_fd.get(), LOCK_EX | LOCK_NB) != 0) {
            PLOG(ERROR) << "flock(" << out_oat_path << ") failed";
            _exit(DexoptReturnCodes::kFlock);
        }

        run_dex2oat(input_fd.get(),
                    out_oat_fd.get(),
                    in_vdex_fd.get(),
                    out_vdex_fd.get(),
@@ -1943,19 +1925,6 @@ int dexopt(const char* dex_path, uid_t uid, const char* pkgname, const char* ins
                    generate_compact_dex,
                    dex_metadata_fd.get(),
                    compilation_reason);

    pid_t pid = fork();
    if (pid == 0) {
        /* child -- drop privileges before continuing */
        drop_capabilities(uid);

        SetDex2OatScheduling(boot_complete);
        if (flock(out_oat_fd.get(), LOCK_EX | LOCK_NB) != 0) {
            PLOG(ERROR) << "flock(" << out_oat_path << ") failed";
            _exit(DexoptReturnCodes::kFlock);
        }

        runner.Exec(DexoptReturnCodes::kDex2oatExec);
    } else {
        int res = wait_child(pid);
        if (res == 0) {
@@ -2519,13 +2488,11 @@ static bool create_app_profile_snapshot(int32_t app_id,
        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 @@ static bool create_boot_image_profile_snapshot(const std::string& package_name,
                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 @@ static bool create_boot_image_profile_snapshot(const std::string& package_name,

            // 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 @@ bool prepare_app_profile(const std::string& package_name,
        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 @@ bool prepare_app_profile(const std::string& package_name,
        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 */