diff options
| author | 2022-02-23 18:33:26 +0000 | |
|---|---|---|
| committer | 2022-03-15 18:37:38 +0000 | |
| commit | f515a1b9264c7c5b2e881c2046b4978bcd3b2c62 (patch) | |
| tree | 4b87f9d900cad6bd2eb3969f9a8e2894cde6eb61 | |
| parent | 3b7c2c61752b3580c110aebeb48508c162e13641 (diff) | |
Use speed-profile with the cloud profile for apks loaded by other apps.
- Add `getOdexVisibility`, which returns the visibility of the odex file
of an APK.
- Change `prepareAppProfile` to accept `userId` being `USER_NULL`. This
is needed by the corresponding change in framework/base, which passes
`USER_NULL` as `userId` to indicate that the current profile should
remain unchanged.
Bug: 175039995
Test: atest CtsCompilationTestCases
Ignore-AOSP-First: Merge conflicts.
Change-Id: I6a9a1077cee6a6d6d02ac2375da55c4a10b11861
| -rw-r--r-- | cmds/installd/InstalldNativeService.cpp | 18 | ||||
| -rw-r--r-- | cmds/installd/InstalldNativeService.h | 5 | ||||
| -rw-r--r-- | cmds/installd/binder/android/os/IInstalld.aidl | 3 | ||||
| -rw-r--r-- | cmds/installd/dexopt.cpp | 46 | ||||
| -rw-r--r-- | cmds/installd/dexopt.h | 13 | ||||
| -rw-r--r-- | cmds/installd/installd_constants.h | 11 | ||||
| -rw-r--r-- | cmds/installd/tests/installd_dexopt_test.cpp | 109 |
7 files changed, 176 insertions, 29 deletions
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp index 7eb5cb4172..3cdba0661d 100644 --- a/cmds/installd/InstalldNativeService.cpp +++ b/cmds/installd/InstalldNativeService.cpp @@ -3631,5 +3631,23 @@ binder::Status InstalldNativeService::cleanupInvalidPackageDirs( return ok(); } +binder::Status InstalldNativeService::getOdexVisibility( + const std::string& packageName, const std::string& apkPath, + const std::string& instructionSet, const std::optional<std::string>& outputPath, + int32_t* _aidl_return) { + ENFORCE_UID(AID_SYSTEM); + CHECK_ARGUMENT_PACKAGE_NAME(packageName); + CHECK_ARGUMENT_PATH(apkPath); + CHECK_ARGUMENT_PATH(outputPath); + LOCK_PACKAGE(); + + const char* apk_path = apkPath.c_str(); + const char* instruction_set = instructionSet.c_str(); + const char* oat_dir = outputPath ? outputPath->c_str() : nullptr; + + *_aidl_return = get_odex_visibility(apk_path, instruction_set, oat_dir); + return *_aidl_return == -1 ? error() : ok(); +} + } // namespace installd } // namespace android diff --git a/cmds/installd/InstalldNativeService.h b/cmds/installd/InstalldNativeService.h index 1f0fc9cf0f..7d19505e07 100644 --- a/cmds/installd/InstalldNativeService.h +++ b/cmds/installd/InstalldNativeService.h @@ -183,6 +183,11 @@ public: binder::Status cleanupInvalidPackageDirs(const std::optional<std::string>& uuid, int32_t userId, int32_t flags); + binder::Status getOdexVisibility(const std::string& packageName, const std::string& apkPath, + const std::string& instructionSet, + const std::optional<std::string>& outputPath, + int32_t* _aidl_return); + private: std::recursive_mutex mLock; std::unordered_map<userid_t, std::weak_ptr<std::shared_mutex>> mUserIdLock; diff --git a/cmds/installd/binder/android/os/IInstalld.aidl b/cmds/installd/binder/android/os/IInstalld.aidl index e08e9b6634..2b5a35e191 100644 --- a/cmds/installd/binder/android/os/IInstalld.aidl +++ b/cmds/installd/binder/android/os/IInstalld.aidl @@ -130,6 +130,9 @@ interface IInstalld { void cleanupInvalidPackageDirs(@nullable @utf8InCpp String uuid, int userId, int flags); + int getOdexVisibility(@utf8InCpp String packageName, @utf8InCpp String apkPath, + @utf8InCpp String instructionSet, @nullable @utf8InCpp String outputPath); + const int FLAG_STORAGE_DE = 0x1; const int FLAG_STORAGE_CE = 0x2; const int FLAG_STORAGE_EXTERNAL = 0x4; diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp index 9647865e4f..894c7d34bd 100644 --- a/cmds/installd/dexopt.cpp +++ b/cmds/installd/dexopt.cpp @@ -2773,13 +2773,23 @@ bool prepare_app_profile(const std::string& package_name, const std::string& profile_name, const std::string& code_path, const std::optional<std::string>& dex_metadata) { - // Prepare the current profile. - std::string cur_profile = create_current_profile_path(user_id, package_name, profile_name, - /*is_secondary_dex*/ false); - uid_t uid = multiuser_get_uid(user_id, app_id); - if (fs_prepare_file_strict(cur_profile.c_str(), 0600, uid, uid) != 0) { - PLOG(ERROR) << "Failed to prepare " << cur_profile; - return false; + if (user_id != USER_NULL) { + if (user_id < 0) { + LOG(ERROR) << "Unexpected user ID " << user_id; + return false; + } + + // Prepare the current profile. + std::string cur_profile = create_current_profile_path(user_id, package_name, profile_name, + /*is_secondary_dex*/ false); + uid_t uid = multiuser_get_uid(user_id, app_id); + if (fs_prepare_file_strict(cur_profile.c_str(), 0600, uid, uid) != 0) { + PLOG(ERROR) << "Failed to prepare " << cur_profile; + return false; + } + } else { + // Prepare the reference profile as the system user. + user_id = USER_SYSTEM; } // Check if we need to install the profile from the dex metadata. @@ -2788,8 +2798,9 @@ bool prepare_app_profile(const std::string& package_name, } // We have a dex metdata. Merge the profile into the reference profile. - unique_fd ref_profile_fd = open_reference_profile(uid, package_name, profile_name, - /*read_write*/ true, /*is_secondary_dex*/ false); + unique_fd ref_profile_fd = + open_reference_profile(multiuser_get_uid(user_id, app_id), package_name, profile_name, + /*read_write*/ true, /*is_secondary_dex*/ false); unique_fd dex_metadata_fd(TEMP_FAILURE_RETRY( open(dex_metadata->c_str(), O_RDONLY | O_NOFOLLOW))); unique_fd apk_fd(TEMP_FAILURE_RETRY(open(code_path.c_str(), O_RDONLY | O_NOFOLLOW))); @@ -2823,5 +2834,22 @@ bool prepare_app_profile(const std::string& package_name, return true; } +int get_odex_visibility(const char* apk_path, const char* instruction_set, const char* oat_dir) { + char oat_path[PKG_PATH_MAX]; + if (!create_oat_out_path(apk_path, instruction_set, oat_dir, /*is_secondary_dex=*/false, + oat_path)) { + return -1; + } + struct stat st; + if (stat(oat_path, &st) == -1) { + if (errno == ENOENT) { + return ODEX_NOT_FOUND; + } + PLOG(ERROR) << "Could not stat " << oat_path; + return -1; + } + return (st.st_mode & S_IROTH) ? ODEX_IS_PUBLIC : ODEX_IS_PRIVATE; +} + } // namespace installd } // namespace android diff --git a/cmds/installd/dexopt.h b/cmds/installd/dexopt.h index 12579b04fc..f7af929e6d 100644 --- a/cmds/installd/dexopt.h +++ b/cmds/installd/dexopt.h @@ -98,10 +98,9 @@ bool copy_system_profile(const std::string& system_profile, const std::string& pkgname, const std::string& profile_name); -// Prepare the app profile for the given code path: -// - create the current profile using profile_name -// - merge the profile from the dex metadata file (if present) into -// the reference profile. +// Prepares the app profile for the package at the given path: +// - Creates the current profile for the given user ID, unless the user ID is `USER_NULL`. +// - Merges the profile from the dex metadata file (if present) into the reference profile. bool prepare_app_profile(const std::string& package_name, userid_t user_id, appid_t app_id, @@ -153,6 +152,12 @@ const char* select_execution_binary( bool is_release, bool is_debuggable_build); +// Returns `ODEX_NOT_FOUND` if the optimized artifacts are not found, or `ODEX_IS_PUBLIC` if the +// optimized artifacts are accessible by all apps, or `ODEX_IS_PRIVATE` if the optimized artifacts +// are only accessible by this app, or -1 if failed to get the visibility of the optimized +// artifacts. +int get_odex_visibility(const char* apk_path, const char* instruction_set, const char* oat_dir); + } // namespace installd } // namespace android diff --git a/cmds/installd/installd_constants.h b/cmds/installd/installd_constants.h index 00d8441607..3623f9b884 100644 --- a/cmds/installd/installd_constants.h +++ b/cmds/installd/installd_constants.h @@ -18,6 +18,8 @@ #ifndef INSTALLD_CONSTANTS_H_ #define INSTALLD_CONSTANTS_H_ +#include "cutils/multiuser.h" + namespace android { namespace installd { @@ -83,6 +85,15 @@ constexpr int PROFILES_ANALYSIS_OPTIMIZE = 1; constexpr int PROFILES_ANALYSIS_DONT_OPTIMIZE_SMALL_DELTA = 2; constexpr int PROFILES_ANALYSIS_DONT_OPTIMIZE_EMPTY_PROFILES = 3; +// NOTE: keep in sync with Installer.java +constexpr int ODEX_NOT_FOUND = 0; +constexpr int ODEX_IS_PUBLIC = 1; +constexpr int ODEX_IS_PRIVATE = 2; + +// NOTE: keep in sync with UserHandle.java +constexpr userid_t USER_NULL = -10000; +constexpr userid_t USER_SYSTEM = 0; + #define ARRAY_SIZE(a) (sizeof(a) / sizeof(*(a))) } // namespace installd diff --git a/cmds/installd/tests/installd_dexopt_test.cpp b/cmds/installd/tests/installd_dexopt_test.cpp index f21a304a3e..4eb30e2542 100644 --- a/cmds/installd/tests/installd_dexopt_test.cpp +++ b/cmds/installd/tests/installd_dexopt_test.cpp @@ -650,6 +650,36 @@ protected: ASSERT_EQ(expected_bytes_freed, bytes_freed); } + + void checkVisibility(bool in_dalvik_cache, int32_t expected_visibility) { + int32_t visibility; + ASSERT_BINDER_SUCCESS(service_->getOdexVisibility(package_name_, apk_path_, kRuntimeIsa, + in_dalvik_cache + ? std::nullopt + : std::make_optional<std::string>( + app_oat_dir_.c_str()), + &visibility)); + EXPECT_EQ(visibility, expected_visibility); + } + + void TestGetOdexVisibility(bool in_dalvik_cache) { + const char* oat_dir = in_dalvik_cache ? nullptr : app_oat_dir_.c_str(); + + checkVisibility(in_dalvik_cache, ODEX_NOT_FOUND); + + CompilePrimaryDexOk("speed-profile", + DEXOPT_BOOTCOMPLETE | DEXOPT_PROFILE_GUIDED | DEXOPT_PUBLIC | + DEXOPT_GENERATE_APP_IMAGE, + oat_dir, kTestAppGid, DEX2OAT_FROM_SCRATCH, + /*binder_result=*/nullptr, empty_dm_file_.c_str()); + checkVisibility(in_dalvik_cache, ODEX_IS_PUBLIC); + + CompilePrimaryDexOk("speed-profile", + DEXOPT_BOOTCOMPLETE | DEXOPT_PROFILE_GUIDED | DEXOPT_GENERATE_APP_IMAGE, + oat_dir, kTestAppGid, DEX2OAT_FROM_SCRATCH, + /*binder_result=*/nullptr, empty_dm_file_.c_str()); + checkVisibility(in_dalvik_cache, ODEX_IS_PRIVATE); + } }; @@ -830,6 +860,16 @@ TEST_F(DexoptTest, DeleteDexoptArtifactsDalvikCache) { TestDeleteOdex(/*in_dalvik_cache=*/ true); } +TEST_F(DexoptTest, GetOdexVisibilityData) { + LOG(INFO) << "GetOdexVisibilityData"; + TestGetOdexVisibility(/*in_dalvik_cache=*/false); +} + +TEST_F(DexoptTest, GetOdexVisibilityDalvikCache) { + LOG(INFO) << "GetOdexVisibilityDalvikCache"; + TestGetOdexVisibility(/*in_dalvik_cache=*/true); +} + TEST_F(DexoptTest, ResolveStartupConstStrings) { LOG(INFO) << "DexoptDex2oatResolveStartupStrings"; const std::string property = "persist.device_config.runtime.dex2oat_resolve_startup_strings"; @@ -1105,13 +1145,16 @@ class ProfileTest : public DexoptTest { ASSERT_TRUE(AreFilesEqual(ref_profile_content, ref_profile_)); } - // TODO(calin): add dex metadata tests once the ART change is merged. void preparePackageProfile(const std::string& package_name, const std::string& profile_name, - bool expected_result) { + bool has_dex_metadata, bool has_user_id, bool expected_result) { bool result; - ASSERT_BINDER_SUCCESS(service_->prepareAppProfile( - package_name, kTestUserId, kTestAppId, profile_name, apk_path_, - /*dex_metadata*/ {}, &result)); + ASSERT_BINDER_SUCCESS( + service_->prepareAppProfile(package_name, has_user_id ? kTestUserId : USER_NULL, + kTestAppId, profile_name, apk_path_, + has_dex_metadata ? std::make_optional<std::string>( + empty_dm_file_) + : std::nullopt, + &result)); ASSERT_EQ(expected_result, result); if (!expected_result) { @@ -1119,16 +1162,29 @@ class ProfileTest : public DexoptTest { return; } - std::string code_path_cur_prof = create_current_profile_path( - kTestUserId, package_name, profile_name, /*is_secondary_dex*/ false); - std::string code_path_ref_profile = create_reference_profile_path(package_name, - profile_name, /*is_secondary_dex*/ false); + std::string code_path_cur_prof = + create_current_profile_path(kTestUserId, package_name, profile_name, + /*is_secondary_dex*/ false); + std::string code_path_ref_profile = + create_reference_profile_path(package_name, profile_name, + /*is_secondary_dex*/ false); - // Check that we created the current profile. - CheckFileAccess(code_path_cur_prof, kTestAppUid, kTestAppUid, 0600 | S_IFREG); + if (has_user_id) { + // Check that we created the current profile. + CheckFileAccess(code_path_cur_prof, kTestAppUid, kTestAppUid, 0600 | S_IFREG); + } else { + // Without a user ID, we don't generate a current profile. + ASSERT_EQ(-1, access(code_path_cur_prof.c_str(), R_OK)); + } - // Without dex metadata we don't generate a reference profile. - ASSERT_EQ(-1, access(code_path_ref_profile.c_str(), R_OK)); + if (has_dex_metadata) { + int32_t uid = has_user_id ? kTestAppUid : multiuser_get_uid(USER_SYSTEM, kTestAppId); + // Check that we created the reference profile. + CheckFileAccess(code_path_ref_profile, uid, uid, 0640 | S_IFREG); + } else { + // Without dex metadata, we don't generate a reference profile. + ASSERT_EQ(-1, access(code_path_ref_profile.c_str(), R_OK)); + } } protected: @@ -1273,12 +1329,32 @@ TEST_F(ProfileTest, ProfileDirOkAfterFixup) { TEST_F(ProfileTest, ProfilePrepareOk) { LOG(INFO) << "ProfilePrepareOk"; - preparePackageProfile(package_name_, "split.prof", /*expected_result*/ true); + preparePackageProfile(package_name_, "split.prof", /*has_dex_metadata*/ true, + /*has_user_id*/ true, /*expected_result*/ true); +} + +TEST_F(ProfileTest, ProfilePrepareOkNoUser) { + LOG(INFO) << "ProfilePrepareOk"; + preparePackageProfile(package_name_, "split.prof", /*has_dex_metadata*/ true, + /*has_user_id*/ false, /*expected_result*/ true); +} + +TEST_F(ProfileTest, ProfilePrepareOkNoDm) { + LOG(INFO) << "ProfilePrepareOk"; + preparePackageProfile(package_name_, "split.prof", /*has_dex_metadata*/ false, + /*has_user_id*/ true, /*expected_result*/ true); +} + +TEST_F(ProfileTest, ProfilePrepareOkNoUserNoDm) { + LOG(INFO) << "ProfilePrepareOk"; + preparePackageProfile(package_name_, "split.prof", /*has_dex_metadata*/ false, + /*has_user_id*/ false, /*expected_result*/ true); } TEST_F(ProfileTest, ProfilePrepareFailInvalidPackage) { LOG(INFO) << "ProfilePrepareFailInvalidPackage"; - preparePackageProfile("not.there.package", "split.prof", /*expected_result*/ false); + preparePackageProfile("not.there.package", "split.prof", /*has_dex_metadata*/ true, + /*has_user_id*/ true, /*expected_result*/ false); } TEST_F(ProfileTest, ProfilePrepareFailProfileChangedUid) { @@ -1286,7 +1362,8 @@ TEST_F(ProfileTest, ProfilePrepareFailProfileChangedUid) { SetupProfiles(/*setup_ref*/ false); // Change the uid on the profile to trigger a failure. ::chown(cur_profile_.c_str(), kTestAppUid + 1, kTestAppGid + 1); - preparePackageProfile(package_name_, "primary.prof", /*expected_result*/ false); + preparePackageProfile(package_name_, "primary.prof", /*has_dex_metadata*/ true, + /*has_user_id*/ true, /*expected_result*/ false); } |