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
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index 7eb5cb4..3cdba06 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -3631,5 +3631,23 @@
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 1f0fc9c..7d19505 100644
--- a/cmds/installd/InstalldNativeService.h
+++ b/cmds/installd/InstalldNativeService.h
@@ -183,6 +183,11 @@
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 e08e9b6..2b5a35e 100644
--- a/cmds/installd/binder/android/os/IInstalld.aidl
+++ b/cmds/installd/binder/android/os/IInstalld.aidl
@@ -130,6 +130,9 @@
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 9647865..894c7d3 100644
--- a/cmds/installd/dexopt.cpp
+++ b/cmds/installd/dexopt.cpp
@@ -2773,13 +2773,23 @@
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 @@
}
// 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 @@
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 12579b0..f7af929 100644
--- a/cmds/installd/dexopt.h
+++ b/cmds/installd/dexopt.h
@@ -98,10 +98,9 @@
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 @@
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 00d8441..3623f9b 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_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 f21a304..4eb30e2 100644
--- a/cmds/installd/tests/installd_dexopt_test.cpp
+++ b/cmds/installd/tests/installd_dexopt_test.cpp
@@ -650,6 +650,36 @@
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 @@
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 @@
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 @@
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, 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 @@
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);
}