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

Commit cc66c449 authored by Mathieu Chartier's avatar Mathieu Chartier
Browse files

Revert "Revert "Refactor argument creation to be before the fork""

Fixed incorrect closing of unique_fds.

Test: atest InstallDexMetadataHostTest
Test: adb shell data/nativetest/installd_dexopt_test/installd_dexopt_test
Bug: 119264994

This reverts commit 3163652b.

Change-Id: I36862f8c4cafa61b0a6db4102138f1ae07427095
parent 13ad9e89
Loading
Loading
Loading
Loading
+415 −372
Original line number Diff line number Diff line
@@ -201,24 +201,54 @@ static const char* get_location_from_path(const char* path) {
    }
}

// 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());
// 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());
        }
    // Add null terminator.
    argv.push_back(nullptr);
    execv(bin, (char * const *)&argv[0]);
        argv_.push_back(nullptr);  // Add null terminator.
    }

static inline void AddArgIfNonEmpty(const std::string& arg, std::vector<std::string>* args) {
    DCHECK(args != nullptr);
    [[ 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);
            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,
                                    const std::string& default_value = "") {
@@ -229,13 +259,28 @@ static std::string MapPropertyToArg(const std::string& property,
  return "";
}

[[ 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) {
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);

@@ -286,15 +331,15 @@ static void run_dex2oat(int zip_fd, int oat_fd, int input_vdex_fd, int output_vd
        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 &&
            android::base::GetBoolProperty(kMinidebugInfoSystemProperty,
                                           kMinidebugInfoSystemPropertyDefault);
                GetBoolProperty(kMinidebugInfoSystemProperty, kMinidebugInfoSystemPropertyDefault);

        // clang FORTIFY doesn't let us use strlen in constant array bounds, so we
        // use arraysize instead.
@@ -314,7 +359,8 @@ static void run_dex2oat(int zip_fd, int oat_fd, int input_vdex_fd, int output_vd
        }
        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) {
@@ -369,72 +415,64 @@ static void run_dex2oat(int zip_fd, int oat_fd, int input_vdex_fd, int output_vd
        // 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);
    };
        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);

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

        if (have_dex2oat_relocation_skip_flag) {
        add_runtime_arg(dex2oat_norelocation);
            AddRuntimeArg(dex2oat_norelocation);
        }
    AddArgIfNonEmpty(profile_arg, &args);
    AddArgIfNonEmpty(base_dir, &args);
    AddArgIfNonEmpty(class_loader_context_arg, &args);
        AddArg(profile_arg);
        AddArg(base_dir);
        AddArg(class_loader_context_arg);
        if (generate_minidebug_info) {
        args.push_back(kMinidebugDex2oatFlag);
            AddArg(kMinidebugDex2oatFlag);
        }
        if (disable_cdex) {
        args.push_back(kDisableCompactDexFlag);
            AddArg(kDisableCompactDexFlag);
        }
    AddArgIfNonEmpty(target_sdk_version_arg, &args);
        AddArg(target_sdk_version_arg);
        if (enable_hidden_api_checks) {
        add_runtime_arg("-Xhidden-api-checks");
            AddRuntimeArg("-Xhidden-api-checks");
        }

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

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

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

    ExecVWithArgs(dex2oat_bin, args);
    PLOG(ERROR) << "execv(" << dex2oat_bin << ") failed";
    exit(DexoptReturnCodes::kDex2oatExec);
        PrepareArgs(dex2oat_bin);
    }
};

/*
 * Whether dexopt should use a swap file when compiling an APK.
@@ -610,75 +648,92 @@ 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;

[[ noreturn ]]
static void run_profman(const std::vector<unique_fd>& profile_fds,
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,
                  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(apk_fds != nullptr);
        CHECK_EQ(1u, apk_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()));
        }
    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) {
        args.push_back("--profile-file-fd=" + std::to_string(fd.get()));
            AddArg("--profile-file-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 unique_fd& fd : apk_fds) {
            AddArg("--apk-fd=" + std::to_string(fd.get()));
        }

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

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

        // 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 */
        PrepareArgs(profman_bin);
    }

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

[[ noreturn ]]
static void run_profman_copy_and_update(unique_fd&& profile_fd,
    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;
    apk_fds.push_back(std::move(apk_fd));
    std::vector<std::string> dex_locations;
    dex_locations.push_back(dex_location);
        // The fds need to stay open longer than the scope of the function, so put them into a local
        // variable vector.
        profiles_fd_.push_back(std::move(profile_fd));
        apk_fds_.push_back(std::move(apk_fd));
        reference_profile_fd_ = std::move(reference_profile_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);
    }

    run_profman(profiles_fd, reference_profile_fd, &apk_fds, &dex_locations,
            /*copy_and_update*/true);
    void Exec() {
        ExecVHelper::Exec(DexoptReturnCodes::kProfmanExec);
    }

  private:
    unique_fd reference_profile_fd_;
    std::vector<unique_fd> profiles_fd_;
    std::vector<unique_fd> apk_fds_;
};



// 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.
// Returns true if there is enough information in the current profiles that makes it
@@ -697,11 +752,13 @@ 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);
        run_profman_merge(profiles_fd, reference_profile_fd);
        profman_merge.Exec();
    }
    /* parent */
    int return_code = wait_child(pid);
@@ -774,35 +831,6 @@ 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;
@@ -839,12 +867,13 @@ 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);
        run_profman_dump(profile_fds, reference_profile_fd, dex_locations,
                         apk_fds, output_fd);
        profman_dump.Exec();
    }
    /* parent */
    int return_code = wait_child(pid);
@@ -1416,9 +1445,16 @@ 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.
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,
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 =
@@ -1440,31 +1476,29 @@ static void exec_dexoptanalyzer(const std::string& dex_file, int vdex_fd, int oa
        }

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

    ExecVWithArgs(dexoptanalyzer_bin, args);
    ALOGE("execv(%s) failed: %s\n", dexoptanalyzer_bin, strerror(errno));
        PrepareArgs(dexoptanalyzer_bin);
    }
};

// Prepares the oat dir for the secondary dex files.
static bool prepare_secondary_dex_oat_dir(const std::string& dex_path, int uid,
@@ -1716,7 +1750,9 @@ 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.
        exec_dexoptanalyzer(dex_path,
        // 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(),
@@ -1724,8 +1760,7 @@ static bool process_secondary_dex_dexopt(const std::string& dex_path, const char
                                              compiler_filter, profile_was_updated,
                                              downgrade,
                                              class_loader_context);
        PLOG(ERROR) << "Failed to exec dexoptanalyzer";
        _exit(kSecondaryDexDexoptAnalyzerSkippedFailExec);
        run_dexopt_analyzer.Exec(kSecondaryDexDexoptAnalyzerSkippedFailExec);
    }

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

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

    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(),
    RunDex2Oat runner(input_fd.get(),
                      out_oat_fd.get(),
                      in_vdex_fd.get(),
                      out_vdex_fd.get(),
@@ -1925,6 +1949,19 @@ 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) {
@@ -2488,11 +2525,13 @@ 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);
        run_profman_merge(profiles_fd, snapshot_fd, &apk_fds, &dex_locations);
        args.Exec();
    }

    /* parent */
@@ -2572,6 +2611,8 @@ 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 */
@@ -2579,7 +2620,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.
            run_profman_merge(profiles_fd, snapshot_fd, &apk_fds, &dex_locations);
            args.Exec();
        }

        /* parent */
@@ -2633,6 +2674,11 @@ 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 */
@@ -2640,10 +2686,7 @@ bool prepare_app_profile(const std::string& package_name,
        drop_capabilities(app_shared_gid);

        // The copy and update takes ownership over the fds.
        run_profman_copy_and_update(std::move(dex_metadata_fd),
                                    std::move(ref_profile_fd),
                                    std::move(apk_fd),
                                    code_path);
        args.Exec();
    }

    /* parent */