From 6727c2d0bfc876c62d6ee60d8a05d26bef1d56ef Mon Sep 17 00:00:00 2001 From: David Sehr Date: Tue, 17 May 2016 16:06:22 -0700 Subject: [PATCH] installd support for profman --dump-info-for Bug: 28748264 Change-Id: Idcd3ed86294c1d0c75c26ca938b88744a25e387a --- cmds/installd/commands.cpp | 111 +++++++++++++++++++++++++++++++++++++++++++-- cmds/installd/commands.h | 2 + cmds/installd/installd.cpp | 14 ++++++ 3 files changed, 124 insertions(+), 3 deletions(-) diff --git a/cmds/installd/commands.cpp b/cmds/installd/commands.cpp index 34b570a092..55e9521317 100644 --- a/cmds/installd/commands.cpp +++ b/cmds/installd/commands.cpp @@ -29,6 +29,7 @@ #include #include +#include #include #include #include @@ -1085,7 +1086,7 @@ 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; -static void run_profman(const std::vector& profiles_fd, fd_t reference_profile_fd) { +static void run_profman_merge(const std::vector& profiles_fd, fd_t reference_profile_fd) { static const size_t MAX_INT_LEN = 32; static const char* PROFMAN_BIN = "/system/bin/profman"; @@ -1133,13 +1134,13 @@ static bool analyse_profiles(uid_t uid, const char* pkgname) { return false; } - ALOGV("PROFMAN: --- BEGIN '%s' ---\n", pkgname); + ALOGV("PROFMAN (MERGE): --- BEGIN '%s' ---\n", pkgname); pid_t pid = fork(); if (pid == 0) { /* child -- drop privileges before continuing */ drop_capabilities(uid); - run_profman(profiles_fd, reference_profile_fd); + run_profman_merge(profiles_fd, reference_profile_fd); exit(68); /* only get here on exec failure */ } /* parent */ @@ -1199,6 +1200,110 @@ static bool analyse_profiles(uid_t uid, const char* pkgname) { return need_to_compile; } +static void run_profman_dump(const std::vector& profile_fds, + fd_t reference_profile_fd, + const std::vector& code_locations, + const std::vector& code_location_fds, + fd_t output_fd) { + static const char* PROFMAN_BIN = "/system/bin/profman"; + const bool has_reference_profile = (reference_profile_fd != -1); + // program name + // --dump-only + // --dump-output-to-fd= + // (optionally, --reference-profile-file-fd=) + const size_t fixed_args = (has_reference_profile ? 4 : 3); + // Fixed arguments, profiles, code paths, code path fds, and final NULL. + const size_t argc = fixed_args + profile_fds.size() + code_locations.size() + + code_location_fds.size() + 1; + const char **argv = new const char*[argc]; + int i = 0; + argv[i++] = PROFMAN_BIN; + argv[i++] = "--dump-only"; + std::string dump_output = StringPrintf("--dump-output-to-fd=%d", output_fd); + argv[i++] = dump_output.c_str(); + if (has_reference_profile) { + std::string reference = + StringPrintf("--reference-profile-file-fd=%d", reference_profile_fd); + argv[i++] = reference.c_str(); + } + for (fd_t profile_fd : profile_fds) { + std::string profile_arg = StringPrintf("--profile-file-fd=%d", profile_fd); + argv[i++] = strdup(profile_arg.c_str()); + } + for (const std::string& code_location : code_locations) { + std::string path_str = StringPrintf("--code-location=%s", code_location.c_str()); + argv[i++] = strdup(path_str.c_str()); + } + for (fd_t code_location_fd : code_location_fds) { + std::string fd_str = StringPrintf("--code-location-fd=%d", code_location_fd); + argv[i++] = strdup(fd_str.c_str()); + } + argv[i] = NULL; + assert(i == argc - 1); + + execv(PROFMAN_BIN, (char * const *)argv); + ALOGE("execv(%s) failed: %s\n", PROFMAN_BIN, strerror(errno)); + exit(68); /* only get here on exec failure */ +} + +// Dumps the contents of a profile file, using pkgname's dex files for pretty +// printing the result. +bool dump_profile(uid_t uid, const char* pkgname, const char* code_path_string) { + std::vector profile_fds; + fd_t reference_profile_fd = -1; + std::string out_file_name = StringPrintf("/data/misc/profman/%s.txt", pkgname); + + ALOGV("PROFMAN (DUMP): --- BEGIN '%s' ---\n", pkgname); + + open_profile_files(uid, pkgname, &profile_fds, &reference_profile_fd); + + const bool has_reference_profile = (reference_profile_fd != -1); + const bool has_profiles = !profile_fds.empty(); + + if (!has_reference_profile && !has_profiles) { + ALOGE("profman dump: no profiles to dump for '%s'", pkgname); + return false; + } + + fd_t output_fd = open(out_file_name.c_str(), O_WRONLY | O_CREAT | O_NOFOLLOW); + if (fchmod(output_fd, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH) < 0) { + ALOGE("installd cannot chmod '%s' dump_profile\n", out_file_name.c_str()); + return false; + } + std::vector code_locations = base::Split(code_path_string, ";"); + std::vector code_location_fds; + for (const std::string& code_location : code_locations) { + fd_t code_location_fd = open(code_location.c_str(), O_RDONLY | O_NOFOLLOW); + if (code_location_fd == -1) { + ALOGE("installd cannot open '%s'\n", code_location.c_str()); + return false; + } + code_location_fds.push_back(code_location_fd); + } + + pid_t pid = fork(); + if (pid == 0) { + /* child -- drop privileges before continuing */ + drop_capabilities(uid); + run_profman_dump(profile_fds, reference_profile_fd, code_locations, + code_location_fds, output_fd); + exit(68); /* only get here on exec failure */ + } + /* parent */ + close_all_fds(code_location_fds, "code_location_fds"); + close_all_fds(profile_fds, "profile_fds"); + if (close(reference_profile_fd) != 0) { + PLOG(WARNING) << "Failed to close fd for reference profile"; + } + int return_code = wait_child(pid); + if (!WIFEXITED(return_code)) { + LOG(WARNING) << "profman failed for package " << pkgname << ": " + << return_code; + return false; + } + return true; +} + static void trim_extension(char* path) { // Trim the extension. int pos = strlen(path); diff --git a/cmds/installd/commands.h b/cmds/installd/commands.h index 41cc209b56..7a42c5caf7 100644 --- a/cmds/installd/commands.h +++ b/cmds/installd/commands.h @@ -54,6 +54,8 @@ int free_cache(const char *uuid, int64_t free_size); bool merge_profiles(uid_t uid, const char *pkgname); +bool dump_profile(uid_t uid, const char *pkgname, const char *dex_files); + 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* compiler_filter, const char* volume_uuid, const char* shared_libraries); diff --git a/cmds/installd/installd.cpp b/cmds/installd/installd.cpp index e8fce91fd7..061359ea43 100644 --- a/cmds/installd/installd.cpp +++ b/cmds/installd/installd.cpp @@ -282,6 +282,19 @@ static int do_merge_profiles(char **arg, char reply[REPLY_MAX]) return 0; } +static int do_dump_profiles(char **arg, char reply[REPLY_MAX]) +{ + uid_t uid = static_cast(atoi(arg[0])); + const char* pkgname = arg[1]; + const char* dex_files = arg[2]; + if (dump_profile(uid, pkgname, dex_files)) { + strncpy(reply, "true", REPLY_MAX); + } else { + strncpy(reply, "false", REPLY_MAX); + } + return 0; +} + static int do_mark_boot_complete(char **arg, char reply[REPLY_MAX] ATTRIBUTE_UNUSED) { return mark_boot_complete(arg[0] /* instruction set */); @@ -428,6 +441,7 @@ struct cmdinfo cmds[] = { { "linkfile", 3, do_link_file }, { "move_ab", 3, do_move_ab }, { "merge_profiles", 2, do_merge_profiles }, + { "dump_profiles", 3, do_dump_profiles }, }; static int readx(int s, void *_buf, int count) -- 2.11.0