diff options
| -rw-r--r-- | cmds/installd/InstalldNativeService.cpp | 31 | ||||
| -rw-r--r-- | cmds/installd/dexopt.cpp | 129 | ||||
| -rw-r--r-- | cmds/installd/dexopt.h | 32 | ||||
| -rw-r--r-- | cmds/installd/otapreopt.cpp | 4 | ||||
| -rw-r--r-- | cmds/installd/tests/installd_dexopt_test.cpp | 76 | ||||
| -rw-r--r-- | cmds/installd/tests/installd_utils_test.cpp | 36 | ||||
| -rw-r--r-- | cmds/installd/utils.cpp | 25 | ||||
| -rw-r--r-- | cmds/installd/utils.h | 13 |
8 files changed, 227 insertions, 119 deletions
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp index bc91285ef4..8a60754b5b 100644 --- a/cmds/installd/InstalldNativeService.cpp +++ b/cmds/installd/InstalldNativeService.cpp @@ -107,6 +107,10 @@ namespace { constexpr const char* kDump = "android.permission.DUMP"; +// TODO(calin): We can stop hardcoding this here once the PM passes the profile +// name for all profile related operations. +constexpr const char* kPrimaryProfileName = "primary.prof"; + static binder::Status ok() { return binder::Status::ok(); } @@ -384,8 +388,9 @@ static bool prepare_app_profile_dir(const std::string& packageName, int32_t appI PLOG(ERROR) << "Failed to prepare " << profile_dir; return false; } + const std::string profile_file = create_current_profile_path(userId, packageName, - /*is_secondary_dex*/false); + kPrimaryProfileName, /*is_secondary_dex*/false); // read-write only for the app user. if (fs_prepare_file_strict(profile_file.c_str(), 0600, uid, uid) != 0) { PLOG(ERROR) << "Failed to prepare " << profile_file; @@ -546,10 +551,10 @@ binder::Status InstalldNativeService::clearAppProfiles(const std::string& packag std::lock_guard<std::recursive_mutex> lock(mLock); binder::Status res = ok(); - if (!clear_primary_reference_profile(packageName)) { + if (!clear_primary_reference_profile(packageName, kPrimaryProfileName)) { res = error("Failed to clear reference profile for " + packageName); } - if (!clear_primary_current_profiles(packageName)) { + if (!clear_primary_current_profiles(packageName, kPrimaryProfileName)) { res = error("Failed to clear current profiles for " + packageName); } return res; @@ -600,7 +605,7 @@ binder::Status InstalldNativeService::clearAppData(const std::unique_ptr<std::st } } if (!only_cache) { - if (!clear_primary_current_profile(packageName, userId)) { + if (!clear_primary_current_profile(packageName, kPrimaryProfileName, userId)) { res = error("Failed to clear current profile for " + packageName); } } @@ -1869,7 +1874,8 @@ binder::Status InstalldNativeService::copySystemProfile(const std::string& syste ENFORCE_UID(AID_SYSTEM); CHECK_ARGUMENT_PACKAGE_NAME(packageName); std::lock_guard<std::recursive_mutex> lock(mLock); - *_aidl_return = copy_system_profile(systemProfile, packageUid, packageName); + *_aidl_return = copy_system_profile(systemProfile, packageUid, packageName, + kPrimaryProfileName); return ok(); } @@ -1880,29 +1886,29 @@ binder::Status InstalldNativeService::mergeProfiles(int32_t uid, const std::stri CHECK_ARGUMENT_PACKAGE_NAME(packageName); std::lock_guard<std::recursive_mutex> lock(mLock); - *_aidl_return = analyze_primary_profiles(uid, packageName); + *_aidl_return = analyze_primary_profiles(uid, packageName, kPrimaryProfileName); return ok(); } binder::Status InstalldNativeService::createProfileSnapshot(int32_t appId, - const std::string& packageName, const std::string& codePath, bool* _aidl_return) { + const std::string& packageName, const std::string& profileName, bool* _aidl_return) { ENFORCE_UID(AID_SYSTEM); CHECK_ARGUMENT_PACKAGE_NAME(packageName); std::lock_guard<std::recursive_mutex> lock(mLock); - *_aidl_return = create_profile_snapshot(appId, packageName, codePath); + *_aidl_return = create_profile_snapshot(appId, packageName, profileName); return ok(); } binder::Status InstalldNativeService::destroyProfileSnapshot(const std::string& packageName, - const std::string& codePath) { + const std::string& profileName) { ENFORCE_UID(AID_SYSTEM); CHECK_ARGUMENT_PACKAGE_NAME(packageName); std::lock_guard<std::recursive_mutex> lock(mLock); - std::string snapshot = create_snapshot_profile_path(packageName, codePath); + std::string snapshot = create_snapshot_profile_path(packageName, profileName); if ((unlink(snapshot.c_str()) != 0) && (errno != ENOENT)) { - return error("Failed to destroy profile snapshot for " + packageName + ":" + codePath); + return error("Failed to destroy profile snapshot for " + packageName + ":" + profileName); } return ok(); } @@ -1928,9 +1934,10 @@ binder::Status InstalldNativeService::dexopt(const std::string& apkPath, int32_t const char* volume_uuid = uuid ? uuid->c_str() : nullptr; const char* class_loader_context = classLoaderContext ? classLoaderContext->c_str() : nullptr; const char* se_info = seInfo ? seInfo->c_str() : nullptr; + int res = android::installd::dexopt(apk_path, uid, pkgname, instruction_set, dexoptNeeded, oat_dir, dexFlags, compiler_filter, volume_uuid, class_loader_context, se_info, - downgrade, targetSdkVersion); + downgrade, targetSdkVersion, kPrimaryProfileName); return res ? error(res, "Failed to dexopt") : ok(); } diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp index 0f635e0385..b85744fee9 100644 --- a/cmds/installd/dexopt.cpp +++ b/cmds/installd/dexopt.cpp @@ -137,37 +137,43 @@ static bool clear_profile(const std::string& 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)); +// The location is the profile name for primary apks or the dex path for secondary dex files. +static bool clear_reference_profile(const std::string& package_name, const std::string& location, + bool is_secondary_dex) { + return clear_profile(create_reference_profile_path(package_name, location, is_secondary_dex)); } // 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)); +// The location is the profile name for primary apks or the dex path for secondary dex files. +static bool clear_current_profile(const std::string& package_name, const std::string& location, + userid_t user, bool is_secondary_dex) { + return clear_profile(create_current_profile_path(user, package_name, location, + is_secondary_dex)); } // 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); +// The location is the profile name for primary apks or the dex path for secondary dex files. +bool clear_primary_reference_profile(const std::string& package_name, + const std::string& location) { + return clear_reference_profile(package_name, location, /*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) { +// The location is the profile name for primary apks or the dex path for secondary dex files. +bool clear_primary_current_profiles(const std::string& package_name, const std::string& location) { 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, /*is_secondary_dex*/false); + success &= clear_current_profile(package_name, location, 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); +bool clear_primary_current_profile(const std::string& package_name, const std::string& location, + userid_t user) { + return clear_current_profile(package_name, location, user, /*is_secondary_dex*/false); } static int split_count(const char *str) @@ -638,29 +644,31 @@ static unique_fd open_profile(uid_t uid, const std::string& profile, int32_t fla return fd; } -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); +static unique_fd open_current_profile(uid_t uid, userid_t user, const std::string& package_name, + const std::string& location, bool is_secondary_dex) { + std::string profile = create_current_profile_path(user, package_name, location, + is_secondary_dex); return open_profile(uid, profile, O_RDONLY); } -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); +static unique_fd open_reference_profile(uid_t uid, const std::string& package_name, + const std::string& location, bool read_write, bool is_secondary_dex) { + std::string profile = create_reference_profile_path(package_name, location, is_secondary_dex); return open_profile(uid, profile, read_write ? (O_CREAT | O_RDWR) : O_RDONLY); } static unique_fd open_spnashot_profile(uid_t uid, const std::string& package_name, - const std::string& code_path) { - std::string profile = create_snapshot_profile_path(package_name, code_path); + const std::string& location) { + std::string profile = create_snapshot_profile_path(package_name, location); return open_profile(uid, profile, O_CREAT | O_RDWR | O_TRUNC); } -static void open_profile_files(uid_t uid, const std::string& location, bool is_secondary_dex, +static void open_profile_files(uid_t uid, const std::string& package_name, + 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, location, /*read_write*/ true, - is_secondary_dex); + *reference_profile_fd = open_reference_profile(uid, package_name, 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. @@ -671,7 +679,8 @@ static void open_profile_files(uid_t uid, const std::string& location, bool is_s users = get_known_users(/*volume_uuid*/ nullptr); } for (auto user : users) { - unique_fd profile_fd = open_current_profile(uid, user, location, is_secondary_dex); + unique_fd profile_fd = open_current_profile(uid, user, package_name, 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)); @@ -742,10 +751,12 @@ static void run_profman_merge(const std::vector<unique_fd>& profiles_fd, // 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(). -static bool analyze_profiles(uid_t uid, const std::string& location, bool is_secondary_dex) { +static bool analyze_profiles(uid_t uid, const std::string& package_name, + const std::string& location, bool is_secondary_dex) { std::vector<unique_fd> profiles_fd; unique_fd reference_profile_fd; - open_profile_files(uid, location, is_secondary_dex, &profiles_fd, &reference_profile_fd); + open_profile_files(uid, package_name, 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. @@ -807,13 +818,14 @@ static bool analyze_profiles(uid_t uid, const std::string& location, bool is_sec if (should_clear_current_profiles) { 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); + clear_current_profile(package_name, location, multiuser_get_user_id(uid), + is_secondary_dex); } else { - clear_primary_current_profiles(location); + clear_primary_current_profiles(package_name, location); } } if (should_clear_reference_profile) { - clear_reference_profile(location, is_secondary_dex); + clear_reference_profile(package_name, location, is_secondary_dex); } return need_to_compile; } @@ -824,8 +836,9 @@ static bool analyze_profiles(uid_t uid, const std::string& location, bool is_sec // 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); +bool analyze_primary_profiles(uid_t uid, const std::string& package_name, + const std::string& profile_name) { + return analyze_profiles(uid, package_name, profile_name, /*is_secondary_dex*/false); } static void run_profman_dump(const std::vector<unique_fd>& profile_fds, @@ -868,7 +881,8 @@ bool dump_profiles(int32_t uid, const std::string& pkgname, const char* code_pat unique_fd reference_profile_fd; std::string out_file_name = StringPrintf("/data/misc/profman/%s.txt", pkgname.c_str()); - open_profile_files(uid, pkgname, /*is_secondary_dex*/false, + // TODO(calin): get the profile name as a parameter. + open_profile_files(uid, pkgname, "primary.prof", /*is_secondary_dex*/false, &profile_fds, &reference_profile_fd); const bool has_reference_profile = (reference_profile_fd.get() != -1); @@ -918,10 +932,11 @@ bool dump_profiles(int32_t uid, const std::string& pkgname, const char* code_pat } bool copy_system_profile(const std::string& system_profile, - uid_t packageUid, const std::string& data_profile_location) { + uid_t packageUid, const std::string& package_name, const std::string& profile_name) { unique_fd in_fd(open(system_profile.c_str(), O_RDONLY | O_NOFOLLOW | O_CLOEXEC)); unique_fd out_fd(open_reference_profile(packageUid, - data_profile_location, + package_name, + profile_name, /*read_write*/ true, /*secondary*/ false)); if (in_fd.get() < 0) { @@ -929,7 +944,7 @@ bool copy_system_profile(const std::string& system_profile, return false; } if (out_fd.get() < 0) { - PLOG(WARNING) << "Could not open profile " << data_profile_location; + PLOG(WARNING) << "Could not open profile " << package_name; return false; } @@ -942,7 +957,7 @@ bool copy_system_profile(const std::string& system_profile, if (flock(out_fd.get(), LOCK_EX | LOCK_NB) != 0) { if (errno != EWOULDBLOCK) { - PLOG(WARNING) << "Error locking profile " << data_profile_location; + PLOG(WARNING) << "Error locking profile " << package_name; } // This implies that the app owning this profile is running // (and has acquired the lock). @@ -950,13 +965,13 @@ bool copy_system_profile(const std::string& system_profile, // The app never acquires the lock for the reference profiles of primary apks. // Only dex2oat from installd will do that. Since installd is single threaded // we should not see this case. Nevertheless be prepared for it. - PLOG(WARNING) << "Failed to flock " << data_profile_location; + PLOG(WARNING) << "Failed to flock " << package_name; return false; } bool truncated = ftruncate(out_fd.get(), 0) == 0; if (!truncated) { - PLOG(WARNING) << "Could not truncate " << data_profile_location; + PLOG(WARNING) << "Could not truncate " << package_name; } // Copy over data. @@ -970,7 +985,7 @@ bool copy_system_profile(const std::string& system_profile, write(out_fd.get(), buffer, bytes); } if (flock(out_fd.get(), LOCK_UN) != 0) { - PLOG(WARNING) << "Error unlocking profile " << data_profile_location; + PLOG(WARNING) << "Error unlocking profile " << package_name; } // Use _exit since we don't want to run the global destructors in the child. // b/62597429 @@ -1269,8 +1284,8 @@ unique_fd maybe_open_dexopt_swap_file(const char* out_oat_path) { // 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 std::string& pkgname, - const std::string& dex_path, bool profile_guided, bool is_public, int uid, - bool is_secondary_dex) { + const std::string& dex_path, const std::string& profile_name, 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. if (!profile_guided || is_public || (pkgname[0] == '*')) { @@ -1278,10 +1293,11 @@ Dex2oatFileWrapper maybe_open_reference_profile(const std::string& pkgname, } // 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); + const std::string location = is_secondary_dex ? dex_path : profile_name; + unique_fd ufd = open_reference_profile(uid, pkgname, location, /*read_write*/false, + is_secondary_dex); + const auto& cleanup = [pkgname, location, is_secondary_dex]() { + clear_reference_profile(pkgname, location, is_secondary_dex); }; return Dex2oatFileWrapper(ufd.release(), cleanup); } @@ -1737,7 +1753,8 @@ static bool process_secondary_dex_dexopt(const std::string& dex_path, const char } // Analyze profiles. - bool profile_was_updated = analyze_profiles(uid, dex_path, /*is_secondary_dex*/true); + bool profile_was_updated = analyze_profiles(uid, pkgname, dex_path, + /*is_secondary_dex*/true); // Run dexoptanalyzer to get dexopt_needed code. This is not expected to return. exec_dexoptanalyzer(dex_path, @@ -1784,7 +1801,7 @@ static bool process_secondary_dex_dexopt(const std::string& dex_path, const char int dexopt(const char* dex_path, uid_t uid, const char* pkgname, const char* instruction_set, int dexopt_needed, const char* oat_dir, int dexopt_flags, const char* compiler_filter, const char* volume_uuid, const char* class_loader_context, const char* se_info, - bool downgrade, int target_sdk_version) { + bool downgrade, int target_sdk_version, const char* profile_name) { CHECK(pkgname != nullptr); CHECK(pkgname[0] != 0); if ((dexopt_flags & ~DEXOPT_MASK) != 0) { @@ -1873,7 +1890,7 @@ int dexopt(const char* dex_path, uid_t uid, const char* pkgname, const char* ins // Open the reference profile if needed. Dex2oatFileWrapper reference_profile_fd = maybe_open_reference_profile( - pkgname, dex_path, profile_guided, is_public, uid, is_secondary_dex); + pkgname, dex_path, profile_name, profile_guided, is_public, uid, is_secondary_dex); ALOGV("DexInv: --- BEGIN '%s' ---\n", dex_path); @@ -2032,9 +2049,9 @@ bool reconcile_secondary_dex_file(const std::string& dex_path, // Delete profiles. std::string current_profile = create_current_profile_path( - multiuser_get_user_id(uid), dex_path, /*is_secondary*/true); + multiuser_get_user_id(uid), pkgname, dex_path, /*is_secondary*/true); std::string reference_profile = create_reference_profile_path( - dex_path, /*is_secondary*/true); + pkgname, dex_path, /*is_secondary*/true); result = unlink_if_exists(current_profile) && result; result = unlink_if_exists(reference_profile) && result; @@ -2426,18 +2443,18 @@ bool create_cache_path_default(char path[PKG_PATH_MAX], const char *src, } bool create_profile_snapshot(int32_t app_id, const std::string& package_name, - const std::string& code_path) { + const std::string& profile_name) { int app_shared_gid = multiuser_get_shared_gid(/*user_id*/ 0, app_id); - unique_fd snapshot_fd = open_spnashot_profile(AID_SYSTEM, package_name, code_path); + unique_fd snapshot_fd = open_spnashot_profile(AID_SYSTEM, package_name, profile_name); if (snapshot_fd < 0) { return false; } std::vector<unique_fd> profiles_fd; unique_fd reference_profile_fd; - open_profile_files(app_shared_gid, package_name, /*is_secondary_dex*/ false, &profiles_fd, - &reference_profile_fd); + open_profile_files(app_shared_gid, package_name, profile_name, /*is_secondary_dex*/ false, + &profiles_fd, &reference_profile_fd); if (profiles_fd.empty() || (reference_profile_fd.get() < 0)) { return false; } @@ -2455,7 +2472,7 @@ bool create_profile_snapshot(int32_t app_id, const std::string& package_name, /* parent */ int return_code = wait_child(pid); if (!WIFEXITED(return_code)) { - LOG(WARNING) << "profman failed for " << package_name << ":" << code_path; + LOG(WARNING) << "profman failed for " << package_name << ":" << profile_name; return false; } diff --git a/cmds/installd/dexopt.h b/cmds/installd/dexopt.h index b1506c34bf..a2baf60e92 100644 --- a/cmds/installd/dexopt.h +++ b/cmds/installd/dexopt.h @@ -33,24 +33,25 @@ static constexpr int DEX2OAT_FOR_BOOT_IMAGE = 2; static constexpr int DEX2OAT_FOR_FILTER = 3; static constexpr int DEX2OAT_FOR_RELOCATION = 4; -// Clear the reference profile for the primary apk of the given package. -bool clear_primary_reference_profile(const std::string& pkgname); -// 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); -// Clear all current profile for the primary apk of the given package. -bool clear_primary_current_profiles(const std::string& pkgname); - -bool move_ab(const char* apk_path, const char* instruction_set, const char* output_path); +// Clear the reference profile identified by the given profile name. +bool clear_primary_reference_profile(const std::string& pkgname, const std::string& profile_name); +// Clear the current profile identified by the given profile name (for single user). +bool clear_primary_current_profile(const std::string& pkgname, const std::string& profile_name, + userid_t user); +// Clear all current profiles identified by the given profile name (all users). +bool clear_primary_current_profiles(const std::string& pkgname, const std::string& profile_name); // Decide if profile guided compilation is needed or not based on existing profiles. -// The analysis is done for the primary apks (base + splits) of the given package. +// The analysis is done for a single profile name (which corresponds to a single code path). // 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); +bool analyze_primary_profiles(uid_t uid, + const std::string& pkgname, + const std::string& profile_name); -// Create a snapshot of the profile information for the given package and code path. +// Create a snapshot of the profile information for the given package profile. // The profile snapshot is the aggregation of all existing profiles (all current user // profiles & the reference profile) and is meant to capture the all the profile information // without performing a merge into the reference profile which might impact future dex2oat @@ -60,13 +61,14 @@ bool analyze_primary_profiles(uid_t uid, const std::string& pkgname); // The snapshot location is reference_profile_location.snapshot. If a snapshot is already // there, it will be truncated and overwritten. bool create_profile_snapshot(int32_t app_id, const std::string& package, - const std::string& code_path); + const std::string& profile_name); bool dump_profiles(int32_t uid, const std::string& pkgname, const char* code_paths); bool copy_system_profile(const std::string& system_profile, uid_t packageUid, - const std::string& data_profile_location); + const std::string& pkgname, + const std::string& profile_name); bool delete_odex(const char* apk_path, const char* instruction_set, const char* output_path); @@ -82,7 +84,7 @@ bool hash_secondary_dex_file(const std::string& dex_path, 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* compiler_filter, const char* volume_uuid, const char* class_loader_context, const char* se_info, - bool downgrade, int target_sdk_version); + bool downgrade, int target_sdk_version, const char* profile_name); bool calculate_oat_file_path_default(char path[PKG_PATH_MAX], const char *oat_dir, const char *apk_path, const char *instruction_set); @@ -93,6 +95,8 @@ bool calculate_odex_file_path_default(char path[PKG_PATH_MAX], const char *apk_p bool create_cache_path_default(char path[PKG_PATH_MAX], const char *src, const char *instruction_set); +bool move_ab(const char* apk_path, const char* instruction_set, const char* output_path); + } // namespace installd } // namespace android diff --git a/cmds/installd/otapreopt.cpp b/cmds/installd/otapreopt.cpp index dbd70518f5..3e5e832db2 100644 --- a/cmds/installd/otapreopt.cpp +++ b/cmds/installd/otapreopt.cpp @@ -1013,6 +1013,7 @@ private: } // Run dexopt with the parameters of package_parameters_. + // TODO(calin): embed the profile name in the parameters. int Dexopt() { return dexopt(package_parameters_.apk_path, package_parameters_.uid, @@ -1026,7 +1027,8 @@ private: package_parameters_.shared_libraries, package_parameters_.se_info, package_parameters_.downgrade, - package_parameters_.target_sdk_version); + package_parameters_.target_sdk_version, + "primary.prof"); } int RunPreopt() { diff --git a/cmds/installd/tests/installd_dexopt_test.cpp b/cmds/installd/tests/installd_dexopt_test.cpp index ff2950631f..729ac3c378 100644 --- a/cmds/installd/tests/installd_dexopt_test.cpp +++ b/cmds/installd/tests/installd_dexopt_test.cpp @@ -431,17 +431,22 @@ class ProfileTest : public DexoptTest { std::string ref_profile_; std::string snap_profile_; + static constexpr const char* kPrimaryProfile = "primary.prof"; + virtual void SetUp() { DexoptTest::SetUp(); cur_profile_ = create_current_profile_path( - kTestUserId, package_name_, /*is_secondary_dex*/ false); - ref_profile_ = create_reference_profile_path(package_name_, /*is_secondary_dex*/ false); - snap_profile_ = create_snapshot_profile_path(package_name_, "base.jar"); + kTestUserId, package_name_, kPrimaryProfile, /*is_secondary_dex*/ false); + ref_profile_ = create_reference_profile_path(package_name_, kPrimaryProfile, + /*is_secondary_dex*/ false); + snap_profile_ = create_snapshot_profile_path(package_name_, kPrimaryProfile); } - void SetupProfile(const std::string& path, uid_t uid, gid_t gid, mode_t mode, int32_t seed) { - run_cmd("profman --generate-test-profile-seed=" + std::to_string(seed) + - " --generate-test-profile-num-dex=2 --generate-test-profile=" + path); + void SetupProfile(const std::string& path, uid_t uid, gid_t gid, mode_t mode, + int32_t num_dex) { + run_cmd("profman --generate-test-profile-seed=" + std::to_string(num_dex) + + " --generate-test-profile-num-dex=" + std::to_string(num_dex) + + " --generate-test-profile=" + path); ::chmod(path.c_str(), mode); ::chown(path.c_str(), uid, gid); } @@ -449,7 +454,7 @@ class ProfileTest : public DexoptTest { void SetupProfiles(bool setup_ref) { SetupProfile(cur_profile_, kTestAppUid, kTestAppGid, 0600, 1); if (setup_ref) { - SetupProfile(ref_profile_, kTestAppUid, kTestAppGid, 0060, 2); + SetupProfile(ref_profile_, kTestAppUid, kTestAppGid, 0600, 2); } } @@ -457,7 +462,7 @@ class ProfileTest : public DexoptTest { bool expected_result) { bool result; binder::Status binder_result = service_->createProfileSnapshot( - appid, package_name, "base.jar", &result); + appid, package_name, kPrimaryProfile, &result); ASSERT_TRUE(binder_result.isOk()); ASSERT_EQ(expected_result, result); @@ -493,6 +498,32 @@ class ProfileTest : public DexoptTest { ASSERT_TRUE(WIFEXITED(wait_child(pid))); } + void mergePackageProfiles(const std::string& package_name, bool expected_result) { + bool result; + binder::Status binder_result = service_->mergeProfiles( + kTestAppUid, package_name, &result); + ASSERT_TRUE(binder_result.isOk()); + ASSERT_EQ(expected_result, result); + + if (!expected_result) { + // Do not check the files if we expect to fail. + return; + } + + // Check that the snapshot was created witht he expected acess flags. + CheckFileAccess(ref_profile_, kTestAppUid, kTestAppUid, 0600 | S_IFREG); + + // The snapshot should be equivalent to the merge of profiles. + std::string ref_profile_content = ref_profile_ + ".expected"; + run_cmd("rm -f " + ref_profile_content); + run_cmd("touch " + ref_profile_content); + run_cmd("profman --profile-file=" + cur_profile_ + + " --profile-file=" + ref_profile_ + + " --reference-profile-file=" + ref_profile_content); + + ASSERT_TRUE(AreFilesEqual(ref_profile_content, ref_profile_)); + } + private: void TransitionToSystemServer() { ASSERT_TRUE(DropCapabilities(kSystemUid, kSystemGid)); @@ -559,20 +590,43 @@ TEST_F(ProfileTest, ProfileSnapshotDestroySnapshot) { SetupProfiles(/*setup_ref*/ true); createProfileSnapshot(kTestAppId, package_name_, /*expected_result*/ true); - binder::Status binder_result = service_->destroyProfileSnapshot(package_name_, "base.jar"); + binder::Status binder_result = service_->destroyProfileSnapshot(package_name_, kPrimaryProfile); ASSERT_TRUE(binder_result.isOk()); struct stat st; ASSERT_EQ(-1, stat(snap_profile_.c_str(), &st)); ASSERT_EQ(ENOENT, errno); } +TEST_F(ProfileTest, ProfileMergeOk) { + LOG(INFO) << "ProfileMergeOk"; + + SetupProfiles(/*setup_ref*/ true); + mergePackageProfiles(package_name_, /*expected_result*/ true); +} + +// The reference profile is created on the fly. We need to be able to +// merge without one. +TEST_F(ProfileTest, ProfileMergeOkNoReference) { + LOG(INFO) << "ProfileMergeOkNoReference"; + + SetupProfiles(/*setup_ref*/ false); + mergePackageProfiles(package_name_, /*expected_result*/ true); +} + +TEST_F(ProfileTest, ProfileMergeFailWrongPackage) { + LOG(INFO) << "ProfileMergeFailWrongPackage"; + + SetupProfiles(/*setup_ref*/ true); + mergePackageProfiles("not.there", /*expected_result*/ false); +} + TEST_F(ProfileTest, ProfileDirOk) { LOG(INFO) << "ProfileDirOk"; std::string cur_profile_dir = create_primary_current_profile_package_dir_path( kTestUserId, package_name_); std::string cur_profile_file = create_current_profile_path(kTestUserId, package_name_, - /*is_secondary_dex*/false); + kPrimaryProfile, /*is_secondary_dex*/false); std::string ref_profile_dir = create_primary_reference_profile_package_dir_path(package_name_); CheckFileAccess(cur_profile_dir, kTestAppUid, kTestAppUid, 0700 | S_IFDIR); @@ -588,7 +642,7 @@ TEST_F(ProfileTest, ProfileDirOkAfterFixup) { std::string cur_profile_dir = create_primary_current_profile_package_dir_path( kTestUserId, package_name_); std::string cur_profile_file = create_current_profile_path(kTestUserId, package_name_, - /*is_secondary_dex*/false); + kPrimaryProfile, /*is_secondary_dex*/false); std::string ref_profile_dir = create_primary_reference_profile_package_dir_path(package_name_); // Simulate a pre-P setup by changing the owner to kTestAppGid and permissions to 0700. diff --git a/cmds/installd/tests/installd_utils_test.cpp b/cmds/installd/tests/installd_utils_test.cpp index 49da85dcfc..bbff6fb0d7 100644 --- a/cmds/installd/tests/installd_utils_test.cpp +++ b/cmds/installd/tests/installd_utils_test.cpp @@ -337,34 +337,50 @@ TEST_F(UtilsTest, CreateDataRefProfilePackagePath) { } TEST_F(UtilsTest, CreatePrimaryCurrentProfile) { - std::string expected = + std::string expected_base = create_primary_current_profile_package_dir_path(0, "com.example") + "/primary.prof"; - EXPECT_EQ(expected, - create_current_profile_path(/*user*/0, "com.example", /*is_secondary*/false)); + EXPECT_EQ(expected_base, + create_current_profile_path(/*user*/0, "com.example", "primary.prof", + /*is_secondary*/false)); + + std::string expected_split = + create_primary_current_profile_package_dir_path(0, "com.example") + "/split.prof"; + EXPECT_EQ(expected_split, + create_current_profile_path(/*user*/0, "com.example", "split.prof", + /*is_secondary*/false)); } TEST_F(UtilsTest, CreatePrimaryReferenceProfile) { - std::string expected = + std::string expected_base = create_primary_reference_profile_package_dir_path("com.example") + "/primary.prof"; - EXPECT_EQ(expected, - create_reference_profile_path("com.example", /*is_secondary*/false)); + EXPECT_EQ(expected_base, + create_reference_profile_path("com.example", "primary.prof", /*is_secondary*/false)); + + std::string expected_split = + create_primary_reference_profile_package_dir_path("com.example") + "/split.prof"; + EXPECT_EQ(expected_split, + create_reference_profile_path("com.example", "split.prof", /*is_secondary*/false)); } TEST_F(UtilsTest, CreateProfileSnapshot) { - std::string expected = + std::string expected_base = create_primary_reference_profile_package_dir_path("com.example") + "/primary.prof.snapshot"; - EXPECT_EQ(expected, create_snapshot_profile_path("com.example", "base.apk")); + EXPECT_EQ(expected_base, create_snapshot_profile_path("com.example", "primary.prof")); + + std::string expected_split = + create_primary_reference_profile_package_dir_path("com.example") + "/split.prof.snapshot"; + EXPECT_EQ(expected_split, create_snapshot_profile_path("com.example", "split.prof")); } TEST_F(UtilsTest, CreateSecondaryCurrentProfile) { EXPECT_EQ("/data/user/0/com.example/oat/secondary.dex.cur.prof", - create_current_profile_path(/*user*/0, + create_current_profile_path(/*user*/0, "com.example", "/data/user/0/com.example/secondary.dex", /*is_secondary*/true)); } TEST_F(UtilsTest, CreateSecondaryReferenceProfile) { EXPECT_EQ("/data/user/0/com.example/oat/secondary.dex.prof", - create_reference_profile_path( + create_reference_profile_path("com.example", "/data/user/0/com.example/secondary.dex", /*is_secondary*/true)); } diff --git a/cmds/installd/utils.cpp b/cmds/installd/utils.cpp index 61c9c8ff08..f3d94597e8 100644 --- a/cmds/installd/utils.cpp +++ b/cmds/installd/utils.cpp @@ -26,6 +26,7 @@ #include <sys/statvfs.h> #include <android-base/logging.h> +#include <android-base/strings.h> #include <android-base/stringprintf.h> #include <cutils/fs.h> #include <cutils/properties.h> @@ -235,7 +236,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 +256,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 +269,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 +287,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; } diff --git a/cmds/installd/utils.h b/cmds/installd/utils.h index 53910615d9..b18e7ddf2e 100644 --- a/cmds/installd/utils.h +++ b/cmds/installd/utils.h @@ -80,10 +80,17 @@ std::string create_primary_ref_profile_dir_path(); std::string create_primary_reference_profile_package_dir_path(const std::string& package_name); std::string create_current_profile_path( - userid_t user, const std::string& package_name, bool is_secondary_dex); + userid_t user, + const std::string& package_name, + const std::string& location, + bool is_secondary_dex); std::string create_reference_profile_path( - const std::string& package_name, bool is_secondary_dex); -std::string create_snapshot_profile_path(const std::string& package, const std::string& code_path); + const std::string& package_name, + const std::string& location, + bool is_secondary_dex); +std::string create_snapshot_profile_path( + const std::string& package, + const std::string& profile_name); std::vector<userid_t> get_known_users(const char* volume_uuid); |