}
if (property_get_bool("dalvik.vm.usejitprofiles", false)) {
- const std::string profile_path = create_data_user_profile_package_path(userId, pkgname);
+ const std::string profile_dir =
+ create_primary_current_profile_package_dir_path(userId, pkgname);
// read-write-execute only for the app user.
- if (fs_prepare_dir_strict(profile_path.c_str(), 0700, uid, uid) != 0) {
- return error("Failed to prepare " + profile_path);
+ if (fs_prepare_dir_strict(profile_dir.c_str(), 0700, uid, uid) != 0) {
+ return error("Failed to prepare " + profile_dir);
}
- std::string profile_file = create_primary_profile(profile_path);
+ const std::string profile_file = create_current_profile_path(userId, pkgname,
+ /*is_secondary_dex*/false);
// read-write only for the app user.
if (fs_prepare_file_strict(profile_file.c_str(), 0600, uid, uid) != 0) {
- return error("Failed to prepare " + profile_path);
+ return error("Failed to prepare " + profile_file);
}
- const std::string ref_profile_path = create_data_ref_profile_package_path(pkgname);
+ const std::string ref_profile_path =
+ create_primary_reference_profile_package_dir_path(pkgname);
// dex2oat/profman runs under the shared app gid and it needs to read/write reference
// profiles.
int shared_app_gid = multiuser_get_shared_gid(0, appId);
std::lock_guard<std::recursive_mutex> lock(mLock);
binder::Status res = ok();
- if (!clear_reference_profile(packageName)) {
+ if (!clear_primary_reference_profile(packageName)) {
res = error("Failed to clear reference profile for " + packageName);
}
- if (!clear_current_profiles(packageName)) {
+ if (!clear_primary_current_profiles(packageName)) {
res = error("Failed to clear current profiles for " + packageName);
}
return res;
}
}
if (!only_cache) {
- if (!clear_current_profile(packageName, userId)) {
+ if (!clear_primary_current_profile(packageName, userId)) {
res = error("Failed to clear current profile for " + packageName);
}
}
static int destroy_app_reference_profile(const std::string& pkgname) {
return delete_dir_contents_and_dir(
- create_data_ref_profile_package_path(pkgname),
+ create_primary_reference_profile_package_dir_path(pkgname),
/*ignore_if_missing*/ true);
}
static int destroy_app_current_profiles(const std::string& pkgname, userid_t userid) {
return delete_dir_contents_and_dir(
- create_data_user_profile_package_path(userid, pkgname),
+ create_primary_current_profile_package_dir_path(userid, pkgname),
/*ignore_if_missing*/ true);
}
if (delete_dir_contents_and_dir(path, true) != 0) {
res = error("Failed to delete " + path);
}
- path = create_data_user_profile_path(userId);
+ path = create_primary_cur_profile_dir_path(userId);
if (delete_dir_contents_and_dir(path, true) != 0) {
res = error("Failed to delete " + path);
}
ATRACE_END();
ATRACE_BEGIN("profiles");
- auto userProfilePath = create_data_user_profile_package_path(userId, pkgname);
+ auto userProfilePath = create_primary_current_profile_package_dir_path(userId, pkgname);
calculate_tree_size(userProfilePath, &stats.dataSize);
- auto refProfilePath = create_data_ref_profile_package_path(pkgname);
+ auto refProfilePath = create_primary_reference_profile_package_dir_path(pkgname);
calculate_tree_size(refProfilePath, &stats.codeSize);
ATRACE_END();
calculate_tree_size(create_data_dalvik_cache_path(), &stats.codeSize,
sharedGid, -1);
}
- calculate_tree_size(create_data_user_profile_path(userId), &stats.dataSize,
+ calculate_tree_size(create_primary_cur_profile_dir_path(userId), &stats.dataSize,
multiuser_get_uid(userId, appId), -1);
ATRACE_END();
}
ATRACE_END();
ATRACE_BEGIN("profile");
- auto userProfilePath = create_data_user_profile_path(userId);
+ auto userProfilePath = create_primary_cur_profile_dir_path(userId);
calculate_tree_size(userProfilePath, &stats.dataSize, -1, -1, true);
- auto refProfilePath = create_data_ref_profile_path();
+ auto refProfilePath = create_primary_ref_profile_dir_path();
calculate_tree_size(refProfilePath, &stats.codeSize, -1, -1, true);
ATRACE_END();
ATRACE_BEGIN("dalvik");
calculate_tree_size(create_data_dalvik_cache_path(), &stats.codeSize,
-1, -1, true);
- calculate_tree_size(create_data_user_profile_path(userId), &stats.dataSize,
+ calculate_tree_size(create_primary_cur_profile_dir_path(userId), &stats.dataSize,
-1, -1, true);
ATRACE_END();
ATRACE_END();
ATRACE_BEGIN("profile");
- auto userProfilePath = create_data_user_profile_path(userId);
+ auto userProfilePath = create_primary_cur_profile_dir_path(userId);
calculate_tree_size(userProfilePath, &stats.dataSize);
- auto refProfilePath = create_data_ref_profile_path();
+ auto refProfilePath = create_primary_ref_profile_dir_path();
calculate_tree_size(refProfilePath, &stats.codeSize);
ATRACE_END();
ATRACE_BEGIN("dalvik");
calculate_tree_size(create_data_dalvik_cache_path(), &stats.codeSize);
- calculate_tree_size(create_data_user_profile_path(userId), &stats.dataSize);
+ calculate_tree_size(create_primary_cur_profile_dir_path(userId), &stats.dataSize);
ATRACE_END();
}
CHECK_ARGUMENT_PACKAGE_NAME(packageName);
std::lock_guard<std::recursive_mutex> lock(mLock);
- const char* pkgname = packageName.c_str();
- *_aidl_return = analyse_profiles(uid, pkgname);
+ *_aidl_return = analyze_primary_profiles(uid, packageName);
return ok();
}
namespace android {
namespace installd {
+// Deleter using free() for use with std::unique_ptr<>. See also UniqueCPtr<> below.
+struct FreeDelete {
+ // NOTE: Deleting a const object is valid but free() takes a non-const pointer.
+ void operator()(const void* ptr) const {
+ free(const_cast<void*>(ptr));
+ }
+};
+
+// Alias for std::unique_ptr<> that uses the C function free() to delete objects.
+template <typename T>
+using UniqueCPtr = std::unique_ptr<T, FreeDelete>;
+
static unique_fd invalid_unique_fd() {
return unique_fd(-1);
}
return truncated;
}
-bool clear_reference_profile(const std::string& pkgname) {
- std::string reference_profile_dir = create_data_ref_profile_package_path(pkgname);
- std::string reference_profile = create_primary_profile(reference_profile_dir);
- return clear_profile(reference_profile);
+// Clear the reference profile for the given location.
+// The location is the package name for primary apks or the dex path for secondary dex files.
+static bool clear_reference_profile(const std::string& location, bool is_secondary_dex) {
+ return clear_profile(create_reference_profile_path(location, is_secondary_dex));
}
-bool clear_current_profile(const std::string& pkgname, userid_t user) {
- std::string profile_dir = create_data_user_profile_package_path(user, pkgname);
- std::string profile = create_primary_profile(profile_dir);
- return clear_profile(profile);
+// Clear the reference profile for the given location.
+// The location is the package name for primary apks or the dex path for secondary dex files.
+static bool clear_current_profile(const std::string& pkgname, userid_t user,
+ bool is_secondary_dex) {
+ return clear_profile(create_current_profile_path(user, pkgname, is_secondary_dex));
}
-bool clear_current_profiles(const std::string& pkgname) {
+// Clear the reference profile for the primary apk of the given package.
+bool clear_primary_reference_profile(const std::string& pkgname) {
+ return clear_reference_profile(pkgname, /*is_secondary_dex*/false);
+}
+
+// Clear all current profile for the primary apk of the given package.
+bool clear_primary_current_profiles(const std::string& pkgname) {
bool success = true;
+ // For secondary dex files, we don't really need the user but we use it for sanity checks.
std::vector<userid_t> users = get_known_users(/*volume_uuid*/ nullptr);
for (auto user : users) {
- success &= clear_current_profile(pkgname, user);
+ success &= clear_current_profile(pkgname, user, /*is_secondary_dex*/false);
}
return success;
}
+// Clear the current profile for the primary apk of the given package and user.
+bool clear_primary_current_profile(const std::string& pkgname, userid_t user) {
+ return clear_current_profile(pkgname, user, /*is_secondary_dex*/false);
+}
+
static int split_count(const char *str)
{
char *ctx;
}
}
-static unique_fd open_profile_dir(const std::string& profile_dir) {
- unique_fd profile_dir_fd(TEMP_FAILURE_RETRY(open(profile_dir.c_str(),
- O_PATH | O_CLOEXEC | O_DIRECTORY | O_NOFOLLOW)));
- if (profile_dir_fd.get() < 0) {
- // In a multi-user environment, these directories can be created at
- // different points and it's possible we'll attempt to open a profile
- // dir before it exists.
- if (errno != ENOENT) {
- PLOG(ERROR) << "Failed to open profile_dir: " << profile_dir;
+static bool create_profile(int uid, const std::string& profile) {
+ unique_fd fd(TEMP_FAILURE_RETRY(open(profile.c_str(), O_CREAT | O_NOFOLLOW, 0600)));
+ if (fd.get() < 0) {
+ if (errno == EEXIST) {
+ return true;
+ } else {
+ PLOG(ERROR) << "Failed to create profile " << profile;
+ return false;
}
}
- return profile_dir_fd;
+ // Profiles should belong to the app; make sure of that by giving ownership to
+ // the app uid. If we cannot do that, there's no point in returning the fd
+ // since dex2oat/profman will fail with SElinux denials.
+ if (fchown(fd.get(), uid, uid) < 0) {
+ PLOG(ERROR) << "Could not chwon profile " << profile;
+ return false;
+ }
+ return true;
}
-static unique_fd open_primary_profile_file_from_dir(const std::string& profile_dir,
- mode_t open_mode) {
- unique_fd profile_dir_fd = open_profile_dir(profile_dir);
- if (profile_dir_fd.get() < 0) {
- return invalid_unique_fd();
+static unique_fd open_profile(int uid, const std::string& profile, bool read_write) {
+ // Check if we need to open the profile for a read-write operation. If so, we
+ // might need to create the profile since the file might not be there. Reference
+ // profiles are created on the fly so they might not exist beforehand.
+ if (read_write) {
+ if (!create_profile(uid, profile)) {
+ return invalid_unique_fd();
+ }
}
+ int flags = read_write ? O_RDWR : O_RDONLY;
+ // Do not follow symlinks when opening a profile:
+ // - primary profiles should not contain symlinks in their paths
+ // - secondary dex paths should have been already resolved and validated
+ flags |= O_NOFOLLOW;
- std::string profile_file = create_primary_profile(profile_dir);
- unique_fd profile_fd(TEMP_FAILURE_RETRY(open(profile_file.c_str(),
- open_mode | O_NOFOLLOW, 0600)));
- if (profile_fd == -1) {
- // It's not an error if the profile file does not exist.
+ unique_fd fd(TEMP_FAILURE_RETRY(open(profile.c_str(), flags)));
+ if (fd.get() < 0) {
if (errno != ENOENT) {
- PLOG(ERROR) << "Failed to open profile : " << profile_file;
+ // Profiles might be missing for various reasons. For example, in a
+ // multi-user environment, the profile directory for one user can be created
+ // after we start a merge. In this case the current profile for that user
+ // will not be found.
+ // Also, the secondary dex profiles might be deleted by the app at any time,
+ // so we can't we need to prepare if they are missing.
+ PLOG(ERROR) << "Failed to open profile " << profile;
}
+ return invalid_unique_fd();
}
- return profile_fd;
+
+ return fd;
}
-static unique_fd open_primary_profile_file(userid_t user, const std::string& 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 unique_fd open_current_profile(uid_t uid, userid_t user, const std::string& location,
+ bool is_secondary_dex) {
+ std::string profile = create_current_profile_path(user, location, is_secondary_dex);
+ return open_profile(uid, profile, /*read_write*/false);
}
-static unique_fd open_reference_profile(uid_t uid, const std::string& 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;
- unique_fd fd = open_primary_profile_file_from_dir(reference_profile_dir, flags);
- if (fd.get() < 0) {
- return invalid_unique_fd();
- }
- if (read_write) {
- // Fix the owner.
- if (fchown(fd.get(), uid, uid) < 0) {
- return invalid_unique_fd();
- }
- }
- return fd;
+static unique_fd open_reference_profile(uid_t uid, const std::string& location, bool read_write,
+ bool is_secondary_dex) {
+ std::string profile = create_reference_profile_path(location, is_secondary_dex);
+ return open_profile(uid, profile, read_write);
}
-static void open_profile_files(uid_t uid, const std::string& pkgname,
+static void open_profile_files(uid_t uid, const std::string& location, bool is_secondary_dex,
/*out*/ std::vector<unique_fd>* profiles_fd, /*out*/ unique_fd* 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->get() < 0) {
- // We can't access the reference profile file.
- return;
+ *reference_profile_fd = open_reference_profile(uid, location, /*read_write*/ true,
+ is_secondary_dex);
+
+ // For secondary dex files, we don't really need the user but we use it for sanity checks.
+ // Note: the user owning the dex file should be the current user.
+ std::vector<userid_t> users;
+ if (is_secondary_dex){
+ users.push_back(multiuser_get_user_id(uid));
+ } else {
+ users = get_known_users(/*volume_uuid*/ nullptr);
}
-
- std::vector<userid_t> users = get_known_users(/*volume_uuid*/ nullptr);
for (auto user : users) {
- unique_fd profile_fd = open_primary_profile_file(user, pkgname);
+ unique_fd profile_fd = open_current_profile(uid, user, location, is_secondary_dex);
// Add to the lists only if both fds are valid.
if (profile_fd.get() >= 0) {
profiles_fd->push_back(std::move(profile_fd));
}
// 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.
+// The location is the package name for primary apks or the dex path for secondary dex files.
+// Returns true if there is enough information in the current profiles that makes it
+// worth to recompile the given location.
// If the return value is true all the current profiles would have been merged into
// the reference profiles accessible with open_reference_profile().
-bool analyse_profiles(uid_t uid, const std::string& pkgname) {
+static bool analyze_profiles(uid_t uid, const std::string& location, bool is_secondary_dex) {
std::vector<unique_fd> profiles_fd;
unique_fd reference_profile_fd;
- open_profile_files(uid, pkgname, &profiles_fd, &reference_profile_fd);
+ open_profile_files(uid, location, is_secondary_dex, &profiles_fd, &reference_profile_fd);
if (profiles_fd.empty() || (reference_profile_fd.get() < 0)) {
// Skip profile guided compilation because no profiles were found.
// Or if the reference profile info couldn't be opened.
bool should_clear_current_profiles = false;
bool should_clear_reference_profile = false;
if (!WIFEXITED(return_code)) {
- LOG(WARNING) << "profman failed for package " << pkgname << ": " << return_code;
+ LOG(WARNING) << "profman failed for location " << location << ": " << return_code;
} else {
return_code = WEXITSTATUS(return_code);
switch (return_code) {
should_clear_reference_profile = false;
break;
case PROFMAN_BIN_RETURN_CODE_BAD_PROFILES:
- LOG(WARNING) << "Bad profiles for package " << pkgname;
+ LOG(WARNING) << "Bad profiles for location " << location;
need_to_compile = false;
should_clear_current_profiles = true;
should_clear_reference_profile = true;
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;
+ LOG(WARNING) << "IO error while reading profiles for location " << location;
need_to_compile = false;
should_clear_current_profiles = false;
should_clear_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;
+ LOG(WARNING) << "Unknown error code while processing profiles for location "
+ << location << ": " << return_code;
need_to_compile = false;
should_clear_current_profiles = true;
should_clear_reference_profile = true;
}
if (should_clear_current_profiles) {
- clear_current_profiles(pkgname);
+ if (is_secondary_dex) {
+ // For secondary dex files, the owning user is the current user.
+ clear_current_profile(location, multiuser_get_user_id(uid), is_secondary_dex);
+ } else {
+ clear_primary_current_profiles(location);
+ }
}
if (should_clear_reference_profile) {
- clear_reference_profile(pkgname);
+ clear_reference_profile(location, is_secondary_dex);
}
return need_to_compile;
}
+// Decides if profile guided compilation is needed or not based on existing profiles.
+// The analysis is done for the primary apks of the given package.
+// Returns true if there is enough information in the current profiles that makes it
+// worth to recompile 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().
+bool analyze_primary_profiles(uid_t uid, const std::string& pkgname) {
+ return analyze_profiles(uid, pkgname, /*is_secondary_dex*/false);
+}
+
static void run_profman_dump(const std::vector<unique_fd>& profile_fds,
const unique_fd& reference_profile_fd,
const std::vector<std::string>& dex_locations,
unique_fd reference_profile_fd;
std::string out_file_name = StringPrintf("/data/misc/profman/%s.txt", pkgname.c_str());
- open_profile_files(uid, pkgname, &profile_fds, &reference_profile_fd);
+ open_profile_files(uid, pkgname, /*is_secondary_dex*/false,
+ &profile_fds, &reference_profile_fd);
const bool has_reference_profile = (reference_profile_fd.get() != -1);
const bool has_profiles = !profile_fds.empty();
return false;
}
- unique_fd output_fd(open(out_file_name.c_str(), O_WRONLY | O_CREAT | O_TRUNC | O_NOFOLLOW, 0644));
+ unique_fd output_fd(open(out_file_name.c_str(),
+ O_WRONLY | O_CREAT | O_TRUNC | O_NOFOLLOW, 0644));
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;
// Opens the reference profiles if needed.
// Note that the reference profile might not exist so it's OK if the fd will be -1.
-Dex2oatFileWrapper maybe_open_reference_profile(const char* pkgname, bool profile_guided,
- bool is_public, int uid, bool is_secondary_dex) {
+Dex2oatFileWrapper maybe_open_reference_profile(const std::string& pkgname,
+ const std::string& dex_path, bool profile_guided, bool is_public, int uid,
+ bool is_secondary_dex) {
// Public apps should not be compiled with profile information ever. Same goes for the special
// package '*' used for the system server.
- // TODO(calin): add support for writing profiles for secondary dex files
- if (profile_guided && !is_secondary_dex && !is_public && (pkgname[0] != '*')) {
- // Open reference profile in read only mode as dex2oat does not get write permissions.
- const std::string pkgname_str(pkgname);
- unique_fd profile_fd = open_reference_profile(uid, pkgname, /*read_write*/ false);
- return Dex2oatFileWrapper(
- profile_fd.release(),
- [pkgname_str]() {
- clear_reference_profile(pkgname_str.c_str());
- });
- } else {
+ if (!profile_guided || is_public || (pkgname[0] == '*')) {
return Dex2oatFileWrapper();
}
+
+ // Open reference profile in read only mode as dex2oat does not get write permissions.
+ const std::string location = is_secondary_dex ? dex_path : pkgname;
+ unique_fd ufd = open_reference_profile(uid, location, /*read_write*/false, is_secondary_dex);
+ const auto& cleanup = [location, is_secondary_dex]() {
+ clear_reference_profile(location.c_str(), is_secondary_dex);
+ };
+ return Dex2oatFileWrapper(ufd.release(), cleanup);
}
// Opens the vdex files and assigns the input fd to in_vdex_wrapper_fd and the output fd to
}
// Runs (execv) dexoptanalyzer on the given arguments.
-static void exec_dexoptanalyzer(const char* dex_file, const char* instruction_set,
- const char* compiler_filter) {
+// The analyzer will check if the dex_file needs to be (re)compiled to match the compiler_filter.
+// If this is for a profile guided compilation, profile_was_updated will tell whether or not
+// the profile has changed.
+static void exec_dexoptanalyzer(const std::string& dex_file, const char* instruction_set,
+ const char* compiler_filter, bool profile_was_updated) {
static const char* DEXOPTANALYZER_BIN = "/system/bin/dexoptanalyzer";
static const unsigned int MAX_INSTRUCTION_SET_LEN = 7;
char dex_file_arg[strlen("--dex-file=") + PKG_PATH_MAX];
char isa_arg[strlen("--isa=") + MAX_INSTRUCTION_SET_LEN];
char compiler_filter_arg[strlen("--compiler-filter=") + kPropertyValueMax];
+ const char* assume_profile_changed = "--assume-profile-changed";
- sprintf(dex_file_arg, "--dex-file=%s", dex_file);
+ sprintf(dex_file_arg, "--dex-file=%s", dex_file.c_str());
sprintf(isa_arg, "--isa=%s", instruction_set);
sprintf(compiler_filter_arg, "--compiler-filter=%s", compiler_filter);
// program name, dex file, isa, filter, the final NULL
- const char* argv[5];
+ const char* argv[5 + (profile_was_updated ? 1 : 0)];
int i = 0;
argv[i++] = DEXOPTANALYZER_BIN;
argv[i++] = dex_file_arg;
argv[i++] = isa_arg;
argv[i++] = compiler_filter_arg;
+ if (profile_was_updated) {
+ argv[i++] = assume_profile_changed;
+ }
argv[i] = NULL;
execv(DEXOPTANALYZER_BIN, (char * const *)argv);
}
// Prepares the oat dir for the secondary dex files.
-static bool prepare_secondary_dex_oat_dir(const char* dex_path, int uid,
- const char* instruction_set, std::string* oat_dir_out) {
- std::string apk_path_str(dex_path);
- unsigned long dirIndex = apk_path_str.rfind('/');
+static bool prepare_secondary_dex_oat_dir(const std::string& dex_path, int uid,
+ const char* instruction_set, std::string* oat_dir_out) {
+ unsigned long dirIndex = dex_path.rfind('/');
if (dirIndex == std::string::npos) {
LOG(ERROR ) << "Unexpected dir structure for secondary dex " << dex_path;
return false;
}
- std::string apk_dir = apk_path_str.substr(0, dirIndex);
+ std::string dex_dir = dex_path.substr(0, dirIndex);
// Assign the gid to the cache gid so that the oat file storage
// is counted towards the app cache.
}
// Create oat file output directory.
- if (prepare_app_cache_dir(apk_dir, "oat", 02711, uid, cache_gid) != 0) {
+ if (prepare_app_cache_dir(dex_dir, "oat", 02711, uid, cache_gid) != 0) {
LOG(ERROR) << "Could not prepare oat dir for secondary dex: " << dex_path;
return false;
}
char oat_dir[PKG_PATH_MAX];
- snprintf(oat_dir, PKG_PATH_MAX, "%s/oat", apk_dir.c_str());
+ snprintf(oat_dir, PKG_PATH_MAX, "%s/oat", dex_dir.c_str());
oat_dir_out->assign(oat_dir);
// Create oat/isa output directory.
// Verifies the result of dexoptanalyzer executed for the apk_path.
// If the result is valid returns true and sets dexopt_needed_out to a valid value.
// Returns false for errors or unexpected result values.
-static bool process_dexoptanalyzer_result(const char* dex_path, int result,
+static bool process_dexoptanalyzer_result(const std::string& dex_path, int result,
int* dexopt_needed_out) {
// The result values are defined in dexoptanalyzer.
switch (result) {
// be compiled. Returns false for errors (logged) or true if the secondary dex path was process
// successfully.
// When returning true, dexopt_needed_out is assigned a valid OatFileAsssitant::DexOptNeeded
-// code and aot_dir_out is assigned the oat dir path where the oat file should be stored.
-static bool process_secondary_dex_dexopt(const char* dex_path, const char* pkgname,
+// code and oat_dir_out is assigned the oat dir path where the oat file should be stored.
+static bool process_secondary_dex_dexopt(const char* original_dex_path, const char* pkgname,
int dexopt_flags, const char* volume_uuid, int uid, const char* instruction_set,
- const char* compiler_filter, int* dexopt_needed_out, std::string* aot_dir_out) {
+ const char* compiler_filter, int* dexopt_needed_out, std::string* oat_dir_out,
+ std::string* dex_path_out) {
int storage_flag;
if ((dexopt_flags & DEXOPT_STORAGE_CE) != 0) {
return false;
}
+ {
+ // As opposed to the primary apk, secondary dex files might contain symlinks.
+ // Resolve the path before passing it to the validate method to
+ // make sure the verification is done on the real location.
+ UniqueCPtr<char> dex_real_path_cstr(realpath(original_dex_path, nullptr));
+ if (dex_real_path_cstr == nullptr) {
+ PLOG(ERROR) << "Could not get the real path of the secondary dex file "
+ << original_dex_path;
+ return false;
+ } else {
+ dex_path_out->assign(dex_real_path_cstr.get());
+ }
+ }
+ const std::string& dex_path = *dex_path_out;
if (!validate_secondary_dex_path(pkgname, dex_path, volume_uuid, uid, storage_flag)) {
LOG(ERROR) << "Could not validate secondary dex path " << dex_path;
return false;
}
// Check if the path exist. If not, there's nothing to do.
- if (access(dex_path, F_OK) != 0) {
+ if (access(dex_path.c_str(), F_OK) != 0) {
if (errno == ENOENT) {
// Secondary dex files might be deleted any time by the app.
// Nothing to do if that's the case
- ALOGV("Secondary dex does not exist %s", dex_path);
+ ALOGV("Secondary dex does not exist %s", dex_path.c_str());
return NO_DEXOPT_NEEDED;
} else {
PLOG(ERROR) << "Could not access secondary dex " << dex_path;
}
// Prepare the oat directories.
- if (!prepare_secondary_dex_oat_dir(dex_path, uid, instruction_set, aot_dir_out)) {
+ if (!prepare_secondary_dex_oat_dir(dex_path, uid, instruction_set, oat_dir_out)) {
return false;
}
+ // Analyze profiles.
+ bool profile_was_updated = analyze_profiles(uid, dex_path, /*is_secondary_dex*/true);
+
pid_t pid = fork();
if (pid == 0) {
// child -- drop privileges before continuing.
drop_capabilities(uid);
// Run dexoptanalyzer to get dexopt_needed code.
- exec_dexoptanalyzer(dex_path, instruction_set, compiler_filter);
+ exec_dexoptanalyzer(dex_path, instruction_set, compiler_filter, profile_was_updated);
exit(DEXOPTANALYZER_BIN_EXEC_ERROR);
}
// Check if we're dealing with a secondary dex file and if we need to compile it.
std::string oat_dir_str;
+ std::string dex_real_path;
if (is_secondary_dex) {
if (process_secondary_dex_dexopt(dex_path, pkgname, dexopt_flags, volume_uuid, uid,
- instruction_set, compiler_filter, &dexopt_needed, &oat_dir_str)) {
+ instruction_set, compiler_filter, &dexopt_needed, &oat_dir_str, &dex_real_path)) {
oat_dir = oat_dir_str.c_str();
+ dex_path = dex_real_path.c_str();
if (dexopt_needed == NO_DEXOPT_NEEDED) {
return 0; // Nothing to do, report success.
}
maybe_open_app_image(out_oat_path, profile_guided, is_public, uid, is_secondary_dex);
// Open the reference profile if needed.
- Dex2oatFileWrapper reference_profile_fd =
- maybe_open_reference_profile(pkgname, profile_guided, is_public, uid, is_secondary_dex);
+ Dex2oatFileWrapper reference_profile_fd = maybe_open_reference_profile(
+ pkgname, dex_path, profile_guided, is_public, uid, is_secondary_dex);
ALOGV("DexInv: --- BEGIN '%s' ---\n", dex_path);
snprintf(out_oat_isa_dir, PKG_PATH_MAX, "%s/%s", out_oat_dir, isa.c_str());
if (!create_oat_out_path(dex_path.c_str(), isa.c_str(), out_oat_dir,
- /*is_secondary_dex*/ true, out_oat_path)) {
+ /*is_secondary_dex*/true, out_oat_path)) {
LOG(ERROR) << "Could not create oat path for secondary dex " << dex_path;
return false;
}
// Delete the oat/odex file.
char out_path[PKG_PATH_MAX];
if (!create_oat_out_path(apk_path, instruction_set, oat_dir,
- /*is_secondary_dex*/ false, out_path)) {
+ /*is_secondary_dex*/false, out_path)) {
return false;
}