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
diff --git a/cmds/installd/commands.cpp b/cmds/installd/commands.cpp
index 2c5bb1c..e31c6e2 100644
--- a/cmds/installd/commands.cpp
+++ b/cmds/installd/commands.cpp
@@ -24,6 +24,7 @@
#include <sys/resource.h>
#include <sys/stat.h>
#include <sys/types.h>
+#include <sys/wait.h>
#include <sys/xattr.h>
#include <unistd.h>
@@ -56,6 +57,17 @@
#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 @@
// 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 @@
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<userid_t> 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 @@
// TODO: include result once 25796509 is fixed
delete_dir_contents(path);
}
+ unlink_all_profiles(pkgname);
}
return res;
}
@@ -160,6 +221,7 @@
// 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 @@
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 @@
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<int>& profile_files_fd, const std::vector<int>& 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 @@
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 @@
(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 @@
(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);
+ 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 @@
+ (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 @@
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 @@
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 @@
}
}
-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) {
+static void close_all_fds(const std::vector<fd_t>& 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 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 (TEMP_FAILURE_RETRY(lstat(profile_dir.c_str(), &buffer)) == -1) {
+ PLOG(ERROR) << "Failed to lstat profile_dir: " << profile_dir;
+ return -1;
+ }
+
+ 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 profile_dir_fd;
+}
+
+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 lstat code_cache: " << code_cache_path;
+ 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;
+}
+
+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;
}
}
-
- 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;
+ return 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);
+static void open_profile_files(uid_t uid, const char* pkgname,
+ /*out*/ std::vector<fd_t>* 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<userid_t> 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 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);
+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);
+ }
+}
- // 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);
+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<fd_t>& 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<std::string> 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<fd_t> 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";
+ }
+ return false;
+ }
+
+ 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 @@
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 @@
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<int> profile_files_fd;
- std::vector<int> 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 @@
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 @@
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 @@
}
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 @@
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 @@
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);