From 62d218d4b1dc716cb8cb4a369ed679d56eede7a5 Mon Sep 17 00:00:00 2001 From: Mathieu Chartier Date: Mon, 5 Nov 2018 09:34:24 -0800 Subject: Refactor argument creation to be before the fork Since it's not safe to do allocations between the fork and the exec, refactor all of the argument creation to be done before the fork. Test: adb shell data/nativetest/installd_dexopt_test/installd_dexopt_test Change-Id: I97016affb32b7ad908861976a1c46d3c4bd816d7 --- cmds/installd/dexopt.cpp | 771 +++++++++++++++++++++++++---------------------- 1 file changed, 404 insertions(+), 367 deletions(-) (limited to 'cmds/installd/dexopt.cpp') diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp index 90cadb4084..50a2412c6b 100644 --- a/cmds/installd/dexopt.cpp +++ b/cmds/installd/dexopt.cpp @@ -201,23 +201,53 @@ 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& args) { - std::vector 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()); + } + argv_.push_back(nullptr); // Add null terminator. } - // Add null terminator. - argv.push_back(nullptr); - execv(bin, (char * const *)&argv[0]); -} -static inline void AddArgIfNonEmpty(const std::string& arg, std::vector* args) { - DCHECK(args != nullptr); - if (!arg.empty()) { - args->push_back(arg); + [[ 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); + } + } + + // 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 args_; + + // Argument poiners. + std::vector argv_; +}; static std::string MapPropertyToArg(const std::string& property, const std::string& format, @@ -229,212 +259,220 @@ 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) { - // 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"); - - 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_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"); +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); + + 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 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 char* dex2oat_norelocation = "-Xnorelocate"; + + const std::string dex2oat_flags = GetProperty("dalvik.vm.dex2oat-flags", ""); + std::vector 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"; + + 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"); + } - const char *dex2oat_norelocation = "-Xnorelocate"; + 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; + } + } - const std::string dex2oat_flags = GetProperty("dalvik.vm.dex2oat-flags", ""); - std::vector dex2oat_flags_args = SplitBySpaces(dex2oat_flags); - ALOGV("dalvik.vm.dex2oat-flags=%s\n", dex2oat_flags.c_str()); + 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 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 (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); + } - 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); + // 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); + } - std::string image_format_arg; - if (image_fd >= 0) { - image_format_arg = MapPropertyToArg("dalvik.vm.appimageformat", "--image-format=%s"); - } + if (dex2oat_compiler_filter_arg.empty()) { + dex2oat_compiler_filter_arg = MapPropertyToArg("dalvik.vm.dex2oat-filter", + "--compiler-filter=%s"); + } - std::string dex2oat_large_app_threshold_arg = - MapPropertyToArg("dalvik.vm.dex2oat-very-large", "--very-large-app-threshold=%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); + } - // 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; + // 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()); } - } - bool generate_minidebug_info = kEnableMinidebugInfo && - android::base::GetBoolProperty(kMinidebugInfoSystemProperty, - kMinidebugInfoSystemPropertyDefault); + std::string dex_metadata_fd_arg = "--dm-fd=" + std::to_string(dex_metadata_fd); - // 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); - } + std::string compilation_reason_arg = compilation_reason == nullptr + ? "" + : std::string("--compilation-reason=") + compilation_reason; - 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); - } + ALOGV("Running %s in=%s out=%s\n", dex2oat_bin, relative_input_file_name, output_file_name); - // 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"); - } + // 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); - // 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); - } + 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); - // 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()); - } + AddArg(instruction_set_variant_arg); + AddArg(instruction_set_features_arg); - std::string dex_metadata_fd_arg = "--dm-fd=" + std::to_string(dex_metadata_fd); + AddRuntimeArg(dex2oat_Xms_arg); + AddRuntimeArg(dex2oat_Xmx_arg); - std::string compilation_reason_arg = compilation_reason == nullptr - ? "" - : std::string("--compilation-reason=") + compilation_reason; + AddArg(resolve_startup_string_arg); + AddArg(dex2oat_compiler_filter_arg); + AddArg(dex2oat_threads_arg); + AddArg(dex2oat_swap_fd); + AddArg(dex2oat_image_fd); - ALOGV("Running %s in=%s out=%s\n", dex2oat_bin, relative_input_file_name, output_file_name); + if (generate_debug_info) { + AddArg("--generate-debug-info"); + } + if (debuggable) { + AddArg("--debuggable"); + } + AddArg(image_format_arg); + AddArg(dex2oat_large_app_threshold_arg); - // 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); + 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"); + } - std::vector 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); - }; + if (dex_metadata_fd > -1) { + AddArg(dex_metadata_fd_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(compilation_reason_arg); - 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"); - } + // 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()); - if (dex_metadata_fd > -1) { - args.push_back(dex_metadata_fd_arg); + PrepareArgs(dex2oat_bin); } - - 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. @@ -610,74 +648,85 @@ 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& profile_fds, - const unique_fd& reference_profile_fd, - const std::vector* apk_fds, - const std::vector* dex_locations, - bool copy_and_update) { - const char* profman_bin = is_debug_runtime() ? "/system/bin/profmand" : "/system/bin/profman"; +class RunProfman : public ExecVHelper { + public: + void SetupArgs(const std::vector& profile_fds, + const unique_fd& reference_profile_fd, + const std::vector& apk_fds, + const std::vector& 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 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 : profile_fds) { - 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 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"); } + + // Do not add after dex2oat_flags, they should override others for debugging. + PrepareArgs(profman_bin); } - if (copy_and_update) { - args.push_back("--copy-and-update-profile-key"); + void SetupMerge(const std::vector& profiles_fd, + const unique_fd& reference_profile_fd, + const std::vector& apk_fds = std::vector(), + const std::vector& dex_locations = std::vector()) { + SetupArgs(profiles_fd, + reference_profile_fd, + apk_fds, + dex_locations, + /*copy_and_update=*/false); } - // Do not add after dex2oat_flags, they should override others for debugging. + void SetupCopyAndUpdate(unique_fd&& profile_fd, + unique_fd&& reference_profile_fd, + unique_fd&& apk_fd, + const std::string& dex_location) { + std::vector profiles_fd; + profiles_fd.push_back(std::move(profile_fd)); + std::vector apk_fds; + profiles_fd.push_back(std::move(apk_fd)); + std::vector dex_locations = {dex_location}; + SetupArgs(profiles_fd, reference_profile_fd, apk_fds, dex_locations, + /*copy_and_update=*/true); + } - ExecVWithArgs(profman_bin, args); - PLOG(ERROR) << "execv(" << profman_bin << ") failed"; - exit(DexoptReturnCodes::kProfmanExec); /* only get here on exec failure */ -} + void SetupDump(const std::vector& profiles_fd, + const unique_fd& reference_profile_fd, + const std::vector& dex_locations, + const std::vector& 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); + } -[[ noreturn ]] -static void run_profman_merge(const std::vector& profiles_fd, - const unique_fd& reference_profile_fd, - const std::vector* apk_fds = nullptr, - const std::vector* dex_locations = nullptr) { - run_profman(profiles_fd, reference_profile_fd, apk_fds, dex_locations, - /*copy_and_update*/false); -} + void Exec() { + ExecVHelper::Exec(DexoptReturnCodes::kProfmanExec); + } +}; -[[ 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 profiles_fd; - profiles_fd.push_back(std::move(profile_fd)); - std::vector apk_fds; - apk_fds.push_back(std::move(apk_fd)); - std::vector 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. @@ -697,11 +746,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 +825,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& profile_fds, - const unique_fd& reference_profile_fd, - const std::vector& dex_locations, - const std::vector& apk_fds, - const unique_fd& output_fd) { - std::vector 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 profile_fds; @@ -839,12 +861,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,55 +1439,60 @@ 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, - 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 - std::vector 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()); - } +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"; + + 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; + } - ExecVWithArgs(dexoptanalyzer_bin, args); - ALOGE("execv(%s) failed: %s\n", dexoptanalyzer_bin, strerror(errno)); -} + // 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); + } +}; // Prepares the oat dir for the secondary dex files. static bool prepare_secondary_dex_oat_dir(const std::string& dex_path, int uid, @@ -1716,16 +1744,17 @@ 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, - 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); + // 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); } /* parent */ @@ -1894,6 +1923,27 @@ 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(), + 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 */ @@ -1905,26 +1955,7 @@ int dexopt(const char* dex_path, uid_t uid, const char* pkgname, const char* ins _exit(DexoptReturnCodes::kFlock); } - 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); + runner.Exec(DexoptReturnCodes::kDex2oatExec); } else { int res = wait_child(pid); if (res == 0) { @@ -2488,11 +2519,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 +2605,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 +2614,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 +2668,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 +2680,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 */ -- cgit v1.2.3-59-g8ed1b