diff options
author | 2015-12-24 12:36:41 +0200 | |
---|---|---|
committer | 2016-01-19 11:26:12 -0800 | |
commit | 60a794dc845b942907ca035ddc554eb8e0c7ebb6 (patch) | |
tree | 1b9ce80babace091ef8f534f3601b96c3892b1e8 /cmds | |
parent | d644021b37ac57f87bb94e2f4907e8f18e2e979e (diff) |
Add profile guided compilation hooks in installd
Bug: 26080105
Change-Id: I6aaddffe79c55b9a6560c2d6542cf87abbd4fb11
Diffstat (limited to 'cmds')
-rw-r--r-- | cmds/installd/commands.cpp | 161 | ||||
-rw-r--r-- | cmds/installd/commands.h | 3 | ||||
-rw-r--r-- | cmds/installd/installd.cpp | 7 |
3 files changed, 155 insertions, 16 deletions
diff --git a/cmds/installd/commands.cpp b/cmds/installd/commands.cpp index 6b004290cc..7674c45442 100644 --- a/cmds/installd/commands.cpp +++ b/cmds/installd/commands.cpp @@ -592,7 +592,8 @@ static bool check_boolean_property(const char* property_name, bool default_value static void run_dex2oat(int zip_fd, int oat_fd, const char* input_file_name, const char* output_file_name, int swap_fd, const char *instruction_set, - bool vm_safe_mode, bool debuggable, bool post_bootcomplete, bool use_jit) + bool vm_safe_mode, bool debuggable, bool post_bootcomplete, bool use_jit, + const std::vector<int>& profile_files_fd, const std::vector<int>& reference_profile_files_fd) { static const unsigned int MAX_INSTRUCTION_SET_LEN = 7; @@ -602,6 +603,12 @@ static void run_dex2oat(int zip_fd, int oat_fd, const char* input_file_name, return; } + if (profile_files_fd.size() != reference_profile_files_fd.size()) { + ALOGE("Invalid configuration of profile files: pf_size (%zu) != rpf_size (%zu)", + profile_files_fd.size(), reference_profile_files_fd.size()); + return; + } + char dex2oat_Xms_flag[kPropertyValueMax]; bool have_dex2oat_Xms_flag = get_property("dalvik.vm.dex2oat-Xms", dex2oat_Xms_flag, NULL) > 0; @@ -712,6 +719,17 @@ static void run_dex2oat(int zip_fd, int oat_fd, const char* input_file_name, (get_property("dalvik.vm.always_debuggable", prop_buf, "0") > 0) && (prop_buf[0] == '1'); } + std::vector<std::string> profile_file_args(profile_files_fd.size()); + std::vector<std::string> reference_profile_file_args(profile_files_fd.size()); + // "reference-profile-file-fd" is longer than "profile-file-fd" so we can + // use it to set the max length. + char profile_buf[strlen("--reference-profile-file-fd=") + MAX_INT_LEN]; + for (size_t k = 0; k < profile_files_fd.size(); k++) { + sprintf(profile_buf, "--profile-file-fd=%d", profile_files_fd[k]); + profile_file_args[k].assign(profile_buf); + sprintf(profile_buf, "--reference-profile-file-fd=%d", reference_profile_files_fd[k]); + reference_profile_file_args[k].assign(profile_buf); + } ALOGV("Running %s in=%s out=%s\n", DEX2OAT_BIN, input_file_name, output_file_name); @@ -726,7 +744,9 @@ static void run_dex2oat(int zip_fd, int oat_fd, const char* input_file_name, + (have_dex2oat_relocation_skip_flag ? 2 : 0) + (generate_debug_info ? 1 : 0) + (debuggable ? 1 : 0) - + dex2oat_flags_count]; + + dex2oat_flags_count + + profile_files_fd.size() + + reference_profile_files_fd.size()]; int i = 0; argv[i++] = DEX2OAT_BIN; argv[i++] = zip_fd_arg; @@ -770,6 +790,10 @@ static void run_dex2oat(int zip_fd, int oat_fd, const char* input_file_name, argv[i++] = RUNTIME_ARG; argv[i++] = dex2oat_norelocation; } + for (size_t k = 0; k < profile_file_args.size(); k++) { + argv[i++] = profile_file_args[k].c_str(); + argv[i++] = reference_profile_file_args[k].c_str(); + } // Do not add after dex2oat_flags, they should override others for debugging. argv[i] = NULL; @@ -836,8 +860,108 @@ static void SetDex2OatAndPatchOatScheduling(bool set_to_bg) { } } -int dexopt(const char *apk_path, uid_t uid, const char *pkgname, const char *instruction_set, - int dexopt_needed, const char* oat_dir, int dexopt_flags) +constexpr const char* PROFILE_FILE_EXTENSION = ".prof"; +constexpr const char* REFERENCE_PROFILE_FILE_EXTENSION = ".prof.ref"; + +static void close_all_fds(const std::vector<int>& fds, const char* description) { + for (size_t i = 0; i < fds.size(); i++) { + if (close(fds[i]) != 0) { + PLOG(WARNING) << "Failed to close fd for " << description << " at index " << i; + } + } +} + +static int open_code_cache_for_user(userid_t user, const char* volume_uuid, const char* pkgname) { + std::string code_cache_path = + create_data_user_package_path(volume_uuid, user, pkgname) + CODE_CACHE_DIR_POSTFIX; + + struct stat buffer; + // Check that the code cache exists. If not, return and don't log an error. + if (TEMP_FAILURE_RETRY(lstat(code_cache_path.c_str(), &buffer)) == -1) { + if (errno != ENOENT) { + PLOG(ERROR) << "Failed to lstat code_cache: " << code_cache_path; + return -1; + } + } + + int code_cache_fd = open(code_cache_path.c_str(), + O_PATH | O_CLOEXEC | O_DIRECTORY | O_NOFOLLOW); + if (code_cache_fd < 0) { + PLOG(ERROR) << "Failed to open code_cache: " << code_cache_path; + } + return code_cache_fd; +} + +// Keep profile paths in sync with ActivityThread. +static void open_profile_files_for_user(uid_t uid, const char* pkgname, int code_cache_fd, + /*out*/ int* profile_fd, /*out*/ int* reference_profile_fd) { + *profile_fd = -1; + *reference_profile_fd = -1; + std::string profile_file(pkgname); + profile_file += PROFILE_FILE_EXTENSION; + + // Check if the profile exists. If not, early return and don't log an error. + struct stat buffer; + if (TEMP_FAILURE_RETRY(fstatat( + code_cache_fd, profile_file.c_str(), &buffer, AT_SYMLINK_NOFOLLOW)) == -1) { + if (errno != ENOENT) { + PLOG(ERROR) << "Failed to fstatat profile file: " << profile_file; + return; + } + } + + // Open in read-write to allow transfer of information from the current profile + // to the reference profile. + *profile_fd = openat(code_cache_fd, profile_file.c_str(), O_RDWR | O_NOFOLLOW); + if (*profile_fd < 0) { + PLOG(ERROR) << "Failed to open profile file: " << profile_file; + return; + } + + std::string reference_profile(pkgname); + reference_profile += REFERENCE_PROFILE_FILE_EXTENSION; + // Give read-write permissions just for the user (changed with fchown after opening). + // We need write permission because dex2oat will update the reference profile files + // with the content of the corresponding current profile files. + *reference_profile_fd = openat(code_cache_fd, reference_profile.c_str(), + O_CREAT | O_RDWR | O_NOFOLLOW, S_IWUSR | S_IRUSR); + if (*reference_profile_fd < 0) { + close(*profile_fd); + return; + } + if (fchown(*reference_profile_fd, uid, uid) < 0) { + PLOG(ERROR) << "Cannot change reference profile file owner: " << reference_profile; + close(*profile_fd); + *profile_fd = -1; + *reference_profile_fd = -1; + } +} + +static void open_profile_files(const char* volume_uuid, uid_t uid, const char* pkgname, + std::vector<int>* profile_fds, std::vector<int>* reference_profile_fds) { + std::vector<userid_t> users = get_known_users(volume_uuid); + for (auto user : users) { + int code_cache_fd = open_code_cache_for_user(user, volume_uuid, pkgname); + if (code_cache_fd < 0) { + continue; + } + int profile_fd = -1; + int reference_profile_fd = -1; + open_profile_files_for_user( + uid, pkgname, code_cache_fd, &profile_fd, &reference_profile_fd); + close(code_cache_fd); + + // Add to the lists only if both fds are valid. + if ((profile_fd >= 0) && (reference_profile_fd >= 0)) { + profile_fds->push_back(profile_fd); + reference_profile_fds->push_back(reference_profile_fd); + } + } +} + +int dexopt(const char* apk_path, uid_t uid, const char* pkgname, const char* instruction_set, + int dexopt_needed, const char* oat_dir, int dexopt_flags, const char* volume_uuid, + bool use_profiles) { struct utimbuf ut; struct stat input_stat; @@ -851,6 +975,16 @@ int dexopt(const char *apk_path, uid_t uid, const char *pkgname, const char *ins bool debuggable = (dexopt_flags & DEXOPT_DEBUGGABLE) != 0; bool boot_complete = (dexopt_flags & DEXOPT_BOOTCOMPLETE) != 0; bool use_jit = (dexopt_flags & DEXOPT_USEJIT) != 0; + std::vector<int> profile_files_fd; + std::vector<int> reference_profile_files_fd; + if (use_profiles) { + open_profile_files(volume_uuid, uid, pkgname, + &profile_files_fd, &reference_profile_files_fd); + if (profile_files_fd.empty()) { + // Skip profile guided compilation because no profiles were found. + return 0; + } + } if ((dexopt_flags & ~DEXOPT_MASK) != 0) { LOG_FATAL("dexopt flags contains unknown fields\n"); @@ -982,14 +1116,9 @@ int dexopt(const char *apk_path, uid_t uid, const char *pkgname, const char *ins || dexopt_needed == DEXOPT_SELF_PATCHOAT_NEEDED) { run_patchoat(input_fd, out_fd, input_file, out_path, pkgname, instruction_set); } else if (dexopt_needed == DEXOPT_DEX2OAT_NEEDED) { - const char *input_file_name = strrchr(input_file, '/'); - if (input_file_name == NULL) { - input_file_name = input_file; - } else { - input_file_name++; - } - run_dex2oat(input_fd, out_fd, input_file_name, out_path, swap_fd, - instruction_set, vm_safe_mode, debuggable, boot_complete, use_jit); + run_dex2oat(input_fd, out_fd, input_file, out_path, swap_fd, + instruction_set, vm_safe_mode, debuggable, boot_complete, use_jit, + profile_files_fd, reference_profile_files_fd); } else { ALOGE("Invalid dexopt needed: %d\n", dexopt_needed); exit(73); @@ -1014,6 +1143,10 @@ int dexopt(const char *apk_path, uid_t uid, const char *pkgname, const char *ins if (swap_fd != -1) { close(swap_fd); } + if (use_profiles != 0) { + close_all_fds(profile_files_fd, "profile_files_fd"); + close_all_fds(reference_profile_files_fd, "reference_profile_files_fd"); + } return 0; fail: @@ -1024,6 +1157,10 @@ fail: if (input_fd >= 0) { close(input_fd); } + if (use_profiles != 0) { + close_all_fds(profile_files_fd, "profile_files_fd"); + close_all_fds(reference_profile_files_fd, "reference_profile_files_fd"); + } return -1; } diff --git a/cmds/installd/commands.h b/cmds/installd/commands.h index 5510e7be67..ab24ecf568 100644 --- a/cmds/installd/commands.h +++ b/cmds/installd/commands.h @@ -48,7 +48,8 @@ int delete_user(const char *uuid, userid_t userid); int rm_dex(const char *path, const char *instruction_set); int free_cache(const char *uuid, int64_t free_size); int dexopt(const char *apk_path, uid_t uid, const char *pkgName, const char *instruction_set, - int dexopt_needed, const char* oat_dir, int dexopt_flags); + int dexopt_needed, const char* oat_dir, int dexopt_flags, + const char* volume_uuid, bool use_profiles); int mark_boot_complete(const char *instruction_set); int movefiles(); int linklib(const char* uuid, const char* pkgname, const char* asecLibDir, int userId); diff --git a/cmds/installd/installd.cpp b/cmds/installd/installd.cpp index 8542c4ab0b..62b5bb032a 100644 --- a/cmds/installd/installd.cpp +++ b/cmds/installd/installd.cpp @@ -214,9 +214,10 @@ static int do_destroy_app_data(char **arg, char reply[REPLY_MAX] ATTRIBUTE_UNUSE static int do_dexopt(char **arg, char reply[REPLY_MAX] ATTRIBUTE_UNUSED) { - /* apk_path, uid, pkgname, instruction_set, dexopt_needed, oat_dir, dexopt_flags */ + /* apk_path, uid, pkgname, instruction_set, dexopt_needed, oat_dir, dexopt_flags, volume_uuid, + use_profiles */ return dexopt(arg[0], atoi(arg[1]), arg[2], arg[3], atoi(arg[4]), - arg[5], atoi(arg[6])); + arg[5], atoi(arg[6]), parse_null(arg[7]), (atoi(arg[8]) == 0 ? false : true)); } static int do_mark_boot_complete(char **arg, char reply[REPLY_MAX] ATTRIBUTE_UNUSED) @@ -321,7 +322,7 @@ struct cmdinfo cmds[] = { { "move_complete_app", 6, do_move_complete_app }, { "get_app_size", 9, do_get_app_size }, - { "dexopt", 7, do_dexopt }, + { "dexopt", 9, do_dexopt }, { "markbootcomplete", 1, do_mark_boot_complete }, { "rmdex", 2, do_rm_dex }, { "freecache", 2, do_free_cache }, |