summaryrefslogtreecommitdiff
path: root/cmds/installd/utils.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'cmds/installd/utils.cpp')
-rw-r--r--cmds/installd/utils.cpp98
1 files changed, 86 insertions, 12 deletions
diff --git a/cmds/installd/utils.cpp b/cmds/installd/utils.cpp
index 61c9c8ff08..a8c32ed2a5 100644
--- a/cmds/installd/utils.cpp
+++ b/cmds/installd/utils.cpp
@@ -26,7 +26,9 @@
#include <sys/statvfs.h>
#include <android-base/logging.h>
+#include <android-base/strings.h>
#include <android-base/stringprintf.h>
+#include <android-base/unique_fd.h>
#include <cutils/fs.h>
#include <cutils/properties.h>
#include <log/log.h>
@@ -40,7 +42,9 @@
#define DEBUG_XATTRS 0
+using android::base::EndsWith;
using android::base::StringPrintf;
+using android::base::unique_fd;
namespace android {
namespace installd {
@@ -235,7 +239,6 @@ std::string create_data_dalvik_cache_path() {
// Keep profile paths in sync with ActivityThread and LoadedApk.
const std::string PROFILE_EXT = ".prof";
const std::string CURRENT_PROFILE_EXT = ".cur";
-const std::string PRIMARY_PROFILE_NAME = "primary" + PROFILE_EXT;
const std::string SNAPSHOT_PROFILE_EXT = ".snapshot";
// Gets the parent directory and the file name for the given secondary dex path.
@@ -256,8 +259,8 @@ static bool get_secondary_dex_location(const std::string& dex_path,
return true;
}
-std::string create_current_profile_path(userid_t user, const std::string& location,
- bool is_secondary_dex) {
+std::string create_current_profile_path(userid_t user, const std::string& package_name,
+ const std::string& location, bool is_secondary_dex) {
if (is_secondary_dex) {
// Secondary dex current profiles are stored next to the dex files under the oat folder.
std::string dex_dir;
@@ -269,12 +272,14 @@ std::string create_current_profile_path(userid_t user, const std::string& locati
PROFILE_EXT.c_str());
} else {
// Profiles for primary apks are under /data/misc/profiles/cur.
- std::string profile_dir = create_primary_current_profile_package_dir_path(user, location);
- return StringPrintf("%s/%s", profile_dir.c_str(), PRIMARY_PROFILE_NAME.c_str());
+ std::string profile_dir = create_primary_current_profile_package_dir_path(
+ user, package_name);
+ return StringPrintf("%s/%s", profile_dir.c_str(), location.c_str());
}
}
-std::string create_reference_profile_path(const std::string& location, bool is_secondary_dex) {
+std::string create_reference_profile_path(const std::string& package_name,
+ const std::string& location, bool is_secondary_dex) {
if (is_secondary_dex) {
// Secondary dex reference profiles are stored next to the dex files under the oat folder.
std::string dex_dir;
@@ -285,16 +290,15 @@ std::string create_reference_profile_path(const std::string& location, bool is_s
dex_dir.c_str(), dex_name.c_str(), PROFILE_EXT.c_str());
} else {
// Reference profiles for primary apks are stored in /data/misc/profile/ref.
- std::string profile_dir = create_primary_reference_profile_package_dir_path(location);
- return StringPrintf("%s/%s", profile_dir.c_str(), PRIMARY_PROFILE_NAME.c_str());
+ std::string profile_dir = create_primary_reference_profile_package_dir_path(package_name);
+ return StringPrintf("%s/%s", profile_dir.c_str(), location.c_str());
}
}
std::string create_snapshot_profile_path(const std::string& package,
- const std::string& code_path ATTRIBUTE_UNUSED) {
- // TODD(calin): code_path is ignored for now. It will be used when each split gets its own
- // profile file.
- std::string ref_profile = create_reference_profile_path(package, /*is_secondary_dex*/ false);
+ const std::string& profile_name) {
+ std::string ref_profile = create_reference_profile_path(package, profile_name,
+ /*is_secondary_dex*/ false);
return ref_profile + SNAPSHOT_PROFILE_EXT;
}
@@ -984,5 +988,75 @@ int prepare_app_cache_dir(const std::string& parent, const char* name, mode_t ta
return 0;
}
+// Collect all non empty profiles from the given directory and puts then into profile_paths.
+// The profiles are identified based on PROFILE_EXT extension.
+// If a subdirectory or profile file cannot be opened the method logs a warning and moves on.
+// It returns true if there were no errors at all, and false otherwise.
+static bool collect_profiles(DIR* d,
+ const std::string& current_path,
+ std::vector<std::string>* profiles_paths) {
+ int32_t dir_fd = dirfd(d);
+ if (dir_fd < 0) {
+ return false;
+ }
+
+ bool result = true;
+ struct dirent* dir_entry;
+ while ((dir_entry = readdir(d))) {
+ std::string name = dir_entry->d_name;
+ std::string local_path = current_path + "/" + name;
+
+ if (dir_entry->d_type == DT_REG) {
+ // Check if this is a non empty profile file.
+ if (EndsWith(name, PROFILE_EXT)) {
+ struct stat st;
+ if (stat(local_path.c_str(), &st) != 0) {
+ PLOG(WARNING) << "Cannot stat local path " << local_path;
+ result = false;
+ continue;
+ } else if (st.st_size > 0) {
+ profiles_paths->push_back(local_path);
+ }
+ }
+ } else if (dir_entry->d_type == DT_DIR) {
+ // always skip "." and ".."
+ if (name == "." || name == "..") {
+ continue;
+ }
+
+ unique_fd subdir_fd(openat(dir_fd, name.c_str(),
+ O_RDONLY | O_DIRECTORY | O_NOFOLLOW | O_CLOEXEC));
+ if (subdir_fd < 0) {
+ PLOG(WARNING) << "Could not open dir path " << local_path;
+ result = false;
+ continue;
+ }
+
+ DIR* subdir = fdopendir(subdir_fd);
+ if (subdir == NULL) {
+ PLOG(WARNING) << "Could not open dir path " << local_path;
+ result = false;
+ continue;
+ }
+ bool new_result = collect_profiles(subdir, local_path, profiles_paths);
+ result = result && new_result;
+ if (closedir(subdir) != 0) {
+ PLOG(WARNING) << "Could not close dir path " << local_path;
+ }
+ }
+ }
+
+ return result;
+}
+
+bool collect_profiles(std::vector<std::string>* profiles_paths) {
+ DIR* d = opendir(android_profiles_dir.c_str());
+ if (d == NULL) {
+ return false;
+ } else {
+ return collect_profiles(d, android_profiles_dir, profiles_paths);
+ }
+}
+
} // namespace installd
} // namespace android