Loading cmds/installd/dexopt.cpp +367 −404 Original line number Diff line number Diff line Loading @@ -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 = "") { Loading @@ -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); Loading Loading @@ -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. Loading @@ -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) { Loading Loading @@ -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. Loading Loading @@ -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. Loading @@ -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); Loading Loading @@ -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; Loading Loading @@ -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); Loading Loading @@ -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 = Loading @@ -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, Loading Loading @@ -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(), Loading @@ -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 */ Loading Loading @@ -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(), Loading @@ -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) { Loading Loading @@ -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 */ Loading Loading @@ -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 */ Loading @@ -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 */ Loading Loading @@ -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 */ Loading @@ -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 */ Loading Loading
cmds/installd/dexopt.cpp +367 −404 Original line number Diff line number Diff line Loading @@ -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 = "") { Loading @@ -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); Loading Loading @@ -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. Loading @@ -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) { Loading Loading @@ -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. Loading Loading @@ -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. Loading @@ -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); Loading Loading @@ -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; Loading Loading @@ -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); Loading Loading @@ -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 = Loading @@ -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, Loading Loading @@ -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(), Loading @@ -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 */ Loading Loading @@ -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(), Loading @@ -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) { Loading Loading @@ -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 */ Loading Loading @@ -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 */ Loading @@ -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 */ Loading Loading @@ -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 */ Loading @@ -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 */ Loading