From 6a1648e2f161cb1d7c46aa9d27e8062521a9f314 Mon Sep 17 00:00:00 2001 From: Calin Juravle Date: Mon, 1 Feb 2016 12:12:16 +0000 Subject: [PATCH] Extract profile files in their dedicated folder Current profiles (the ones which have not been used for compilation) are stored in /data/misc/profiles/cur/0/pkgname/. Reference profiles (the merged of all user profiles, used for compilation) are stored in /data/misc/profiles/ref/pkgname. The profile analysis flow has been changed to use profman before calling dex2oat. profman decides if there is a need for compilation and does the merging. Bug: 26719109 Bug: 26563023 Bug: 26881016 Change-Id: I5a86ed5fd07a28e2e580f9c108428527ba7993b6 --- cmds/installd/commands.cpp | 484 +++++++++++++++++++++++++------------ cmds/installd/globals.cpp | 6 + cmds/installd/globals.h | 1 + cmds/installd/installd_constants.h | 4 +- cmds/installd/utils.cpp | 31 ++- cmds/installd/utils.h | 5 + 6 files changed, 364 insertions(+), 167 deletions(-) diff --git a/cmds/installd/commands.cpp b/cmds/installd/commands.cpp index 2c5bb1c353..e31c6e20e1 100644 --- a/cmds/installd/commands.cpp +++ b/cmds/installd/commands.cpp @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -56,6 +57,17 @@ static constexpr const char* kXattrDefault = "user.default"; #define MIN_RESTRICTED_HOME_SDK_VERSION 24 // > M +typedef int fd_t; + +static bool property_get_bool(const char* property_name, bool default_value = false) { + char tmp_property_value[kPropertyValueMax]; + bool have_property = get_property(property_name, tmp_property_value, nullptr) > 0; + if (!have_property) { + return default_value; + } + return strcmp(tmp_property_value, "true") == 0; +} + int create_app_data(const char *uuid, const char *pkgname, userid_t userid, int flags, appid_t appid, const char* seinfo, int target_sdk_version) { uid_t uid = multiuser_get_uid(userid, appid); @@ -83,6 +95,24 @@ int create_app_data(const char *uuid, const char *pkgname, userid_t userid, int // TODO: include result once 25796509 is fixed return 0; } + + if (property_get_bool("dalvik.vm.usejitprofiles")) { + const std::string profile_path = create_data_user_profile_package_path(userid, pkgname); + // read-write-execute only for the app user. + if (fs_prepare_dir_strict(profile_path.c_str(), 0700, uid, uid) != 0) { + PLOG(ERROR) << "Failed to prepare " << profile_path; + return -1; + } + const std::string ref_profile_path = create_data_ref_profile_package_path(pkgname); + // dex2oat/profman runs under the shared app gid and it needs to read/write reference + // profiles. + appid_t shared_app_gid = multiuser_get_shared_app_gid(uid); + if (fs_prepare_dir_strict( + ref_profile_path.c_str(), 0700, shared_app_gid, shared_app_gid) != 0) { + PLOG(ERROR) << "Failed to prepare " << ref_profile_path; + return -1; + } + } } return 0; } @@ -125,6 +155,36 @@ int migrate_app_data(const char *uuid, const char *pkgname, userid_t userid, int return 0; } +// Keep profile paths in sync with ActivityThread. +constexpr const char* PRIMARY_PROFILE_NAME = "primary.prof"; +static std::string create_primary_profile(const std::string& profile_dir) { + return StringPrintf("%s/%s", profile_dir.c_str(), PRIMARY_PROFILE_NAME); +} + +static void unlink_reference_profile(const char* pkgname) { + std::string reference_profile_dir = create_data_ref_profile_package_path(pkgname); + std::string reference_profile = create_primary_profile(reference_profile_dir); + if (unlink(reference_profile.c_str()) != 0) { + PLOG(WARNING) << "Could not unlink " << reference_profile; + } +} + +static void unlink_current_profiles(const char* pkgname) { + std::vector users = get_known_users(/*volume_uuid*/ nullptr); + for (auto user : users) { + std::string profile_dir = create_data_user_profile_package_path(user, pkgname); + std::string profile = create_primary_profile(profile_dir); + if (unlink(profile.c_str()) != 0) { + PLOG(WARNING) << "Could not unlink " << profile; + } + } +} + +static void unlink_all_profiles(const char* pkgname) { + unlink_reference_profile(pkgname); + unlink_current_profiles(pkgname); +} + int clear_app_data(const char *uuid, const char *pkgname, userid_t userid, int flags) { std::string suffix = ""; if (flags & FLAG_CLEAR_CACHE_ONLY) { @@ -146,6 +206,7 @@ int clear_app_data(const char *uuid, const char *pkgname, userid_t userid, int f // TODO: include result once 25796509 is fixed delete_dir_contents(path); } + unlink_all_profiles(pkgname); } return res; } @@ -160,6 +221,7 @@ int destroy_app_data(const char *uuid, const char *pkgname, userid_t userid, int // TODO: include result once 25796509 is fixed delete_dir_contents_and_dir( create_data_user_de_package_path(uuid, userid, pkgname)); + unlink_all_profiles(pkgname); } return res; } @@ -289,11 +351,13 @@ int delete_user(const char *uuid, userid_t userid) { std::string data_path(create_data_user_path(uuid, userid)); std::string data_de_path(create_data_user_de_path(uuid, userid)); std::string media_path(create_data_media_path(uuid, userid)); + std::string profiles_path(create_data_user_profiles_path(userid)); res |= delete_dir_contents_and_dir(data_path); // TODO: include result once 25796509 is fixed delete_dir_contents_and_dir(data_de_path); res |= delete_dir_contents_and_dir(media_path); + res |= delete_dir_contents_and_dir(profiles_path); // Config paths only exist on internal storage if (uuid == nullptr) { @@ -630,19 +694,10 @@ static void run_patchoat(int input_fd, int oat_fd, const char* input_file_name, ALOGE("execv(%s) failed: %s\n", PATCHOAT_BIN, strerror(errno)); } -static bool check_boolean_property(const char* property_name, bool default_value = false) { - char tmp_property_value[kPropertyValueMax]; - bool have_property = get_property(property_name, tmp_property_value, nullptr) > 0; - if (!have_property) { - return default_value; - } - return strcmp(tmp_property_value, "true") == 0; -} - static void run_dex2oat(int zip_fd, int oat_fd, int image_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 extract_only, - const std::vector& profile_files_fd, const std::vector& reference_profile_files_fd) { + const char* output_file_name, int swap_fd, const char *instruction_set, + bool vm_safe_mode, bool debuggable, bool post_bootcomplete, bool extract_only, + int profile_fd) { static const unsigned int MAX_INSTRUCTION_SET_LEN = 7; if (strlen(instruction_set) >= MAX_INSTRUCTION_SET_LEN) { @@ -651,12 +706,6 @@ static void run_dex2oat(int zip_fd, int oat_fd, int image_fd, const char* input_ 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; @@ -705,7 +754,7 @@ static void run_dex2oat(int zip_fd, int oat_fd, int image_fd, const char* input_ (strcmp(vold_decrypt, "trigger_restart_min_framework") == 0 || (strcmp(vold_decrypt, "1") == 0))); - bool generate_debug_info = check_boolean_property("debug.generate-debug-info"); + bool generate_debug_info = property_get_bool("debug.generate-debug-info"); char app_image_format[kPropertyValueMax]; char image_format_arg[strlen("--image-format=") + kPropertyValueMax]; @@ -779,18 +828,12 @@ static void run_dex2oat(int zip_fd, int oat_fd, int image_fd, const char* input_ (get_property("dalvik.vm.always_debuggable", prop_buf, "0") > 0) && (prop_buf[0] == '1'); } - std::vector profile_file_args(profile_files_fd.size()); - std::vector 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); + char profile_arg[strlen("--profile-file-fd=") + MAX_INT_LEN]; + if (profile_fd != -1) { + sprintf(profile_arg, "--profile-file-fd=%d", profile_fd); } + ALOGV("Running %s in=%s out=%s\n", DEX2OAT_BIN, input_file_name, output_file_name); const char* argv[7 // program name, mandatory arguments and the final NULL @@ -807,8 +850,7 @@ static void run_dex2oat(int zip_fd, int oat_fd, int image_fd, const char* input_ + (debuggable ? 1 : 0) + (have_app_image_format ? 1 : 0) + dex2oat_flags_count - + profile_files_fd.size() - + reference_profile_files_fd.size()]; + + (profile_fd == -1 ? 0 : 1)]; int i = 0; argv[i++] = DEX2OAT_BIN; argv[i++] = zip_fd_arg; @@ -858,9 +900,8 @@ static void run_dex2oat(int zip_fd, int oat_fd, int image_fd, const char* input_ 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(); + if (profile_fd != -1) { + argv[i++] = profile_arg; } // Do not add after dex2oat_flags, they should override others for debugging. argv[i] = NULL; @@ -906,7 +947,7 @@ static bool ShouldUseSwapFileForDexopt() { return true; } - bool is_low_mem = check_boolean_property("ro.config.low_ram"); + bool is_low_mem = property_get_bool("ro.config.low_ram"); if (is_low_mem) { return true; } @@ -928,10 +969,7 @@ 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& fds, const char* description) { +static void close_all_fds(const std::vector& 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; @@ -939,92 +977,224 @@ static void close_all_fds(const std::vector& fds, const char* description) } } -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_de_package_path(volume_uuid, user, pkgname) + CODE_CACHE_DIR_POSTFIX; - +static fd_t open_profile_dir(const std::string& profile_dir) { 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; - } + if (TEMP_FAILURE_RETRY(lstat(profile_dir.c_str(), &buffer)) == -1) { + PLOG(ERROR) << "Failed to lstat profile_dir: " << profile_dir; + 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; + fd_t profile_dir_fd = TEMP_FAILURE_RETRY(open(profile_dir.c_str(), + O_PATH | O_CLOEXEC | O_DIRECTORY | O_NOFOLLOW)); + if (profile_dir_fd < 0) { + PLOG(ERROR) << "Failed to open profile_dir: " << profile_dir; } - return code_cache_fd; + return profile_dir_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) { +static fd_t open_primary_profile_file_from_dir(const std::string& profile_dir, mode_t open_mode) { + fd_t profile_dir_fd = open_profile_dir(profile_dir); + if (profile_dir_fd < 0) { + return -1; + } + + fd_t profile_fd = -1; + std::string profile_file = create_primary_profile(profile_dir); + + profile_fd = TEMP_FAILURE_RETRY(open(profile_file.c_str(), open_mode | O_NOFOLLOW)); + if (profile_fd == -1) { + // It's not an error if the profile file does not exist. if (errno != ENOENT) { - PLOG(ERROR) << "Failed to fstatat profile file: " << profile_file; - return; + PLOG(ERROR) << "Failed to lstat profile_dir: " << profile_dir; } } + // TODO(calin): use AutoCloseFD instead of closing the fd manually. + if (close(profile_dir_fd) != 0) { + PLOG(WARNING) << "Could not close profile dir " << profile_dir; + } + return profile_fd; +} - // 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; +static fd_t open_primary_profile_file(userid_t user, const char* pkgname) { + std::string profile_dir = create_data_user_profile_package_path(user, pkgname); + return open_primary_profile_file_from_dir(profile_dir, O_RDONLY); +} + +static fd_t open_reference_profile(uid_t uid, const char* pkgname, bool read_write) { + std::string reference_profile_dir = create_data_ref_profile_package_path(pkgname); + int flags = read_write ? O_RDWR | O_CREAT : O_RDONLY; + fd_t fd = open_primary_profile_file_from_dir(reference_profile_dir, flags); + if (fd < 0) { + return -1; } + if (read_write) { + // Fix the owner. + if (fchown(fd, uid, uid) < 0) { + close(fd); + return -1; + } + } + return fd; +} - 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); +static void open_profile_files(uid_t uid, const char* pkgname, + /*out*/ std::vector* profiles_fd, /*out*/ fd_t* reference_profile_fd) { + // Open the reference profile in read-write mode as profman might need to save the merge. + *reference_profile_fd = open_reference_profile(uid, pkgname, /*read_write*/ true); if (*reference_profile_fd < 0) { - close(*profile_fd); + // We can't access the reference profile file. 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; + + std::vector users = get_known_users(/*volume_uuid*/ nullptr); + for (auto user : users) { + fd_t profile_fd = open_primary_profile_file(user, pkgname); + // Add to the lists only if both fds are valid. + if (profile_fd >= 0) { + profiles_fd->push_back(profile_fd); + } + } +} + +static void drop_capabilities(uid_t uid) { + if (setgid(uid) != 0) { + ALOGE("setgid(%d) failed in installd during dexopt\n", uid); + exit(64); + } + if (setuid(uid) != 0) { + ALOGE("setuid(%d) failed in installd during dexopt\n", uid); + exit(65); + } + // drop capabilities + struct __user_cap_header_struct capheader; + struct __user_cap_data_struct capdata[2]; + memset(&capheader, 0, sizeof(capheader)); + memset(&capdata, 0, sizeof(capdata)); + capheader.version = _LINUX_CAPABILITY_VERSION_3; + if (capset(&capheader, &capdata[0]) < 0) { + ALOGE("capset failed: %s\n", strerror(errno)); + exit(66); } } -static void open_profile_files(const char* volume_uuid, uid_t uid, const char* pkgname, - std::vector* profile_fds, std::vector* reference_profile_fds) { - std::vector 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; +static constexpr int PROFMAN_BIN_RETURN_CODE_COMPILE = 0; +static constexpr int PROFMAN_BIN_RETURN_CODE_SKIP_COMPILATION = 1; +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 const size_t MAX_INT_LEN = 32; + static const char* PROFMAN_BIN = "/system/bin/profman"; + + std::vector profile_args(profiles_fd.size()); + char profile_buf[strlen("--profile-file-fd=") + MAX_INT_LEN]; + for (size_t k = 0; k < profiles_fd.size(); k++) { + sprintf(profile_buf, "--profile-file-fd=%d", profiles_fd[k]); + profile_args[k].assign(profile_buf); + } + char reference_profile_arg[strlen("--reference-profile-file-fd=") + MAX_INT_LEN]; + sprintf(reference_profile_arg, "--reference-profile-file-fd=%d", reference_profile_fd); + + // program name, reference profile fd, the final NULL and the profile fds + const char* argv[3 + profiles_fd.size()]; + int i = 0; + argv[i++] = PROFMAN_BIN; + argv[i++] = reference_profile_arg; + for (size_t k = 0; k < profile_args.size(); k++) { + argv[i++] = profile_args[k].c_str(); + } + // Do not add after dex2oat_flags, they should override others for debugging. + argv[i] = NULL; + + execv(PROFMAN_BIN, (char * const *)argv); + ALOGE("execv(%s) failed: %s\n", PROFMAN_BIN, strerror(errno)); + exit(68); /* only get here on exec failure */ +} + +// Decides if profile guided compilation is needed or not based on existing profiles. +// Returns true if there is enough information in the current profiles that worth +// a re-compilation of the package. +// If the return value is true all the current profiles would have been merged into +// the reference profiles accessible with open_reference_profile(). +static bool analyse_profiles(uid_t uid, const char* pkgname) { + std::vector profiles_fd; + fd_t reference_profile_fd = -1; + open_profile_files(uid, pkgname, &profiles_fd, &reference_profile_fd); + if (profiles_fd.empty() || (reference_profile_fd == -1)) { + // Skip profile guided compilation because no profiles were found. + // Or if the reference profile info couldn't be opened. + close_all_fds(profiles_fd, "profiles_fd"); + if ((reference_profile_fd != - 1) && (close(reference_profile_fd) != 0)) { + PLOG(WARNING) << "Failed to close fd for reference profile"; } - 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); + return false; + } - // 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); + ALOGV("PROFMAN: --- 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); + exit(68); /* only get here on exec failure */ + } + /* parent */ + int return_code = wait_child(pid); + bool need_to_compile = false; + bool delete_current_profiles = false; + bool delete_reference_profile = false; + if (!WIFEXITED(return_code)) { + LOG(WARNING) << "profman failed for package " << pkgname << ": " << return_code; + } else { + return_code = WEXITSTATUS(return_code); + switch (return_code) { + case PROFMAN_BIN_RETURN_CODE_COMPILE: + need_to_compile = true; + delete_current_profiles = true; + delete_reference_profile = false; + break; + case PROFMAN_BIN_RETURN_CODE_SKIP_COMPILATION: + need_to_compile = false; + delete_current_profiles = false; + delete_reference_profile = false; + break; + case PROFMAN_BIN_RETURN_CODE_BAD_PROFILES: + LOG(WARNING) << "Bad profiles for package " << pkgname; + need_to_compile = false; + delete_current_profiles = true; + delete_reference_profile = true; + break; + case PROFMAN_BIN_RETURN_CODE_ERROR_IO: // fall-through + case PROFMAN_BIN_RETURN_CODE_ERROR_LOCKING: + // Temporary IO problem (e.g. locking). Ignore but log a warning. + LOG(WARNING) << "IO error while reading profiles for package " << pkgname; + need_to_compile = false; + delete_current_profiles = false; + delete_reference_profile = false; + break; + default: + // Unknown return code or error. Unlink profiles. + LOG(WARNING) << "Unknown error code while processing profiles for package " << pkgname + << ": " << return_code; + need_to_compile = false; + delete_current_profiles = true; + delete_reference_profile = true; + break; } } + close_all_fds(profiles_fd, "profiles_fd"); + if (close(reference_profile_fd) != 0) { + PLOG(WARNING) << "Failed to close fd for reference profile"; + } + if (delete_current_profiles) { + unlink_current_profiles(pkgname); + } + if (delete_reference_profile) { + unlink_reference_profile(pkgname); + } + return need_to_compile; } static void trim_extension(char* path) { @@ -1066,9 +1236,36 @@ static bool set_permissions_and_ownership(int fd, bool is_public, int uid, const return true; } +static bool create_oat_out_path(const char* apk_path, const char* instruction_set, + const char* oat_dir, /*out*/ char* out_path) { + // Early best-effort check whether we can fit the the path into our buffers. + // Note: the cache path will require an additional 5 bytes for ".swap", but we'll try to run + // without a swap file, if necessary. Reference profiles file also add an extra ".prof" + // extension to the cache path (5 bytes). + if (strlen(apk_path) >= (PKG_PATH_MAX - 8)) { + ALOGE("apk_path too long '%s'\n", apk_path); + return false; + } + + if (oat_dir != NULL && oat_dir[0] != '!') { + if (validate_apk_path(oat_dir)) { + ALOGE("invalid oat_dir '%s'\n", oat_dir); + return false; + } + if (!calculate_oat_file_path(out_path, oat_dir, apk_path, instruction_set)) { + return false; + } + } else { + if (!create_cache_path(out_path, apk_path, instruction_set)) { + return false; + } + } + return true; +} + 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) + int dexopt_needed, const char* oat_dir, int dexopt_flags, + const char* volume_uuid ATTRIBUTE_UNUSED, bool use_profiles) { struct utimbuf ut; struct stat input_stat; @@ -1077,19 +1274,25 @@ int dexopt(const char* apk_path, uid_t uid, const char* pkgname, const char* ins char image_path[PKG_PATH_MAX]; const char *input_file; char in_odex_path[PKG_PATH_MAX]; - int res, input_fd=-1, out_fd=-1, image_fd=-1, swap_fd=-1; + int res; + fd_t input_fd=-1, out_fd=-1, image_fd=-1, swap_fd=-1; bool is_public = (dexopt_flags & DEXOPT_PUBLIC) != 0; bool vm_safe_mode = (dexopt_flags & DEXOPT_SAFEMODE) != 0; bool debuggable = (dexopt_flags & DEXOPT_DEBUGGABLE) != 0; bool boot_complete = (dexopt_flags & DEXOPT_BOOTCOMPLETE) != 0; bool extract_only = (dexopt_flags & DEXOPT_EXTRACTONLY) != 0; - std::vector profile_files_fd; - std::vector reference_profile_files_fd; + fd_t reference_profile_fd = -1; 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. + if (analyse_profiles(uid, pkgname)) { + // Open again reference profile in read only mode as dex2oat does not get write + // permissions. + reference_profile_fd = open_reference_profile(uid, pkgname, /*read_write*/ false); + if (reference_profile_fd == -1) { + PLOG(WARNING) << "Couldn't open reference profile in read only mode " << pkgname; + exit(72); + } + } else { + // No need to (re)compile. Return early. return 0; } } @@ -1098,26 +1301,8 @@ int dexopt(const char* apk_path, uid_t uid, const char* pkgname, const char* ins LOG_FATAL("dexopt flags contains unknown fields\n"); } - // Early best-effort check whether we can fit the the path into our buffers. - // Note: the cache path will require an additional 5 bytes for ".swap", but we'll try to run - // without a swap file, if necessary. - if (strlen(apk_path) >= (PKG_PATH_MAX - 8)) { - ALOGE("apk_path too long '%s'\n", apk_path); - return -1; - } - - if (oat_dir != NULL && oat_dir[0] != '!') { - if (validate_apk_path(oat_dir)) { - ALOGE("invalid oat_dir '%s'\n", oat_dir); - return -1; - } - if (!calculate_oat_file_path(out_path, oat_dir, apk_path, instruction_set)) { - return -1; - } - } else { - if (!create_cache_path(out_path, apk_path, instruction_set)) { - return -1; - } + if (!create_oat_out_path(apk_path, instruction_set, oat_dir, out_path)) { + return false; } switch (dexopt_needed) { @@ -1207,24 +1392,8 @@ int dexopt(const char* apk_path, uid_t uid, const char* pkgname, const char* ins pid = fork(); if (pid == 0) { /* child -- drop privileges before continuing */ - if (setgid(uid) != 0) { - ALOGE("setgid(%d) failed in installd during dexopt\n", uid); - exit(64); - } - if (setuid(uid) != 0) { - ALOGE("setuid(%d) failed in installd during dexopt\n", uid); - exit(65); - } - // drop capabilities - struct __user_cap_header_struct capheader; - struct __user_cap_data_struct capdata[2]; - memset(&capheader, 0, sizeof(capheader)); - memset(&capdata, 0, sizeof(capdata)); - capheader.version = _LINUX_CAPABILITY_VERSION_3; - if (capset(&capheader, &capdata[0]) < 0) { - ALOGE("capset failed: %s\n", strerror(errno)); - exit(66); - } + drop_capabilities(uid); + SetDex2OatAndPatchOatScheduling(boot_complete); if (flock(out_fd, LOCK_EX | LOCK_NB) != 0) { ALOGE("flock(%s) failed: %s\n", out_path, strerror(errno)); @@ -1244,7 +1413,7 @@ int dexopt(const char* apk_path, uid_t uid, const char* pkgname, const char* ins } run_dex2oat(input_fd, out_fd, image_fd, input_file_name, out_path, swap_fd, instruction_set, vm_safe_mode, debuggable, boot_complete, extract_only, - profile_files_fd, reference_profile_files_fd); + reference_profile_fd); } else { ALOGE("Invalid dexopt needed: %d\n", dexopt_needed); exit(73); @@ -1269,9 +1438,8 @@ int dexopt(const char* apk_path, uid_t uid, const char* pkgname, const char* ins if (swap_fd >= 0) { 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"); + if (reference_profile_fd >= 0) { + close(reference_profile_fd); } if (image_fd >= 0) { close(image_fd); @@ -1286,9 +1454,11 @@ 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"); + if (reference_profile_fd >= 0) { + close(reference_profile_fd); + // We failed to compile. Unlink the reference profile. Current profiles are already unlinked + // when profmoan advises compilation. + unlink_reference_profile(pkgname); } if (swap_fd >= 0) { close(swap_fd); diff --git a/cmds/installd/globals.cpp b/cmds/installd/globals.cpp index bee2790c2b..6a67e29396 100644 --- a/cmds/installd/globals.cpp +++ b/cmds/installd/globals.cpp @@ -39,6 +39,7 @@ dir_rec_t android_asec_dir; dir_rec_t android_data_dir; dir_rec_t android_media_dir; dir_rec_t android_mnt_expand_dir; +dir_rec_t android_profiles_dir; dir_rec_array_t android_system_dirs; @@ -99,6 +100,11 @@ bool init_globals_from_data_and_root(const char* data, const char* root) { return false; } + // Get the android profiles directory. + if (copy_and_append(&android_profiles_dir, &android_data_dir, PROFILES_SUBDIR) < 0) { + return false; + } + // Take note of the system and vendor directories. android_system_dirs.count = 4; diff --git a/cmds/installd/globals.h b/cmds/installd/globals.h index 2e61f85d6a..3e523460ad 100644 --- a/cmds/installd/globals.h +++ b/cmds/installd/globals.h @@ -43,6 +43,7 @@ extern dir_rec_t android_asec_dir; extern dir_rec_t android_data_dir; extern dir_rec_t android_media_dir; extern dir_rec_t android_mnt_expand_dir; +extern dir_rec_t android_profiles_dir; extern dir_rec_array_t android_system_dirs; diff --git a/cmds/installd/installd_constants.h b/cmds/installd/installd_constants.h index 4e1d38fe56..8f6e928a9d 100644 --- a/cmds/installd/installd_constants.h +++ b/cmds/installd/installd_constants.h @@ -4,7 +4,7 @@ ** ** Licensed under the Apache License, Version 2.0 (the "License"); ** you may not use this file except in compliance with the License. -** You may obtain a copy of the License at +** You may obtain a copy of the License at ** ** http://www.apache.org/licenses/LICENSE-2.0 ** @@ -41,6 +41,8 @@ constexpr const char* APP_LIB_SUBDIR = "app-lib/"; // sub-directory under ANDROI constexpr const char* MEDIA_SUBDIR = "media/"; // sub-directory under ANDROID_DATA +constexpr const char* PROFILES_SUBDIR = "misc/profiles"; // sub-directory under ANDROID_DATA + /* other handy constants */ constexpr const char* PRIVATE_APP_SUBDIR = "app-private/"; // sub-directory under ANDROID_DATA diff --git a/cmds/installd/utils.cpp b/cmds/installd/utils.cpp index d25bf71e95..74f4264f80 100644 --- a/cmds/installd/utils.cpp +++ b/cmds/installd/utils.cpp @@ -59,6 +59,11 @@ static bool is_valid_filename(const std::string& name) { } } +static void check_package_name(const char* package_name) { + CHECK(is_valid_filename(package_name)); + CHECK(is_valid_package_name(package_name) == 0); +} + /** * Create the path name where package app contents should be stored for * the given volume UUID and package name. An empty UUID is assumed to @@ -66,9 +71,7 @@ static bool is_valid_filename(const std::string& name) { */ std::string create_data_app_package_path(const char* volume_uuid, const char* package_name) { - CHECK(is_valid_filename(package_name)); - CHECK(is_valid_package_name(package_name) == 0); - + check_package_name(package_name); return StringPrintf("%s/%s", create_data_app_path(volume_uuid).c_str(), package_name); } @@ -80,18 +83,14 @@ std::string create_data_app_package_path(const char* volume_uuid, */ std::string create_data_user_package_path(const char* volume_uuid, userid_t user, const char* package_name) { - CHECK(is_valid_filename(package_name)); - CHECK(is_valid_package_name(package_name) == 0); - + check_package_name(package_name); return StringPrintf("%s/%s", create_data_user_path(volume_uuid, user).c_str(), package_name); } std::string create_data_user_de_package_path(const char* volume_uuid, userid_t user, const char* package_name) { - CHECK(is_valid_filename(package_name)); - CHECK(is_valid_package_name(package_name) == 0); - + check_package_name(package_name); return StringPrintf("%s/%s", create_data_user_de_path(volume_uuid, user).c_str(), package_name); } @@ -161,6 +160,20 @@ std::string create_data_media_path(const char* volume_uuid, userid_t userid) { return StringPrintf("%s/media/%u", create_data_path(volume_uuid).c_str(), userid); } +std::string create_data_user_profiles_path(userid_t userid) { + return StringPrintf("%s/cur/%u", android_profiles_dir.path, userid); +} + +std::string create_data_user_profile_package_path(userid_t user, const char* package_name) { + check_package_name(package_name); + return StringPrintf("%s/%s",create_data_user_profiles_path(user).c_str(), package_name); +} + +std::string create_data_ref_profile_package_path(const char* package_name) { + check_package_name(package_name); + return StringPrintf("%s/ref/%s", android_profiles_dir.path, package_name); +} + std::vector get_known_users(const char* volume_uuid) { std::vector users; diff --git a/cmds/installd/utils.h b/cmds/installd/utils.h index 2d9573e21b..9bbddcaec9 100644 --- a/cmds/installd/utils.h +++ b/cmds/installd/utils.h @@ -84,6 +84,10 @@ std::string create_data_user_de_package_path(const char* volume_uuid, std::string create_data_media_path(const char* volume_uuid, userid_t userid); +std::string create_data_user_profiles_path(userid_t userid); +std::string create_data_user_profile_package_path(userid_t user, const char* package_name); +std::string create_data_ref_profile_package_path(const char* package_name); + std::vector get_known_users(const char* volume_uuid); int create_user_config_path(char path[PKG_PATH_MAX], userid_t userid); @@ -135,6 +139,7 @@ char *build_string2(const char *s1, const char *s2); char *build_string3(const char *s1, const char *s2, const char *s3); int ensure_dir(const char* path, mode_t mode, uid_t uid, gid_t gid); +int ensure_media_user_dirs(const char* uuid, userid_t userid); int ensure_config_user_dirs(userid_t userid); int wait_child(pid_t pid); -- 2.11.0