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

Commit 60a794dc authored by Calin Juravle's avatar Calin Juravle
Browse files

Add profile guided compilation hooks in installd

Bug: 26080105
Change-Id: I6aaddffe79c55b9a6560c2d6542cf87abbd4fb11
parent d644021b
Loading
Loading
Loading
Loading
+149 −12
Original line number Diff line number Diff line
@@ -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) {
    }
}

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)
           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;
}

+2 −1
Original line number Diff line number Diff line
@@ -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);
+4 −3
Original line number Diff line number Diff line
@@ -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 },