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

Commit 95ea320e authored by Mathieu Chartier's avatar Mathieu Chartier Committed by android-build-merger
Browse files

Merge "Revert "Revert "Refactor argument creation to be before the fork""" am:...

Merge "Revert "Revert "Refactor argument creation to be before the fork""" am: 94d4364d am: bfd7e73d
am: fe2b7f9b

Change-Id: I5e23f3971004d19a40a360f315789a656e233cec
parents bfdc4574 fe2b7f9b
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 */