summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJiakai Zhang <jiakaiz@google.com>2024-04-08 16:51:57 +0100
committerTreehugger Robot <android-test-infra-autosubmit@system.gserviceaccount.com>2024-04-26 16:37:13 +0000
commit75d4422b08058ba92dfdeebc1bbe1f89d591b721 (patch)
treea4b28e536e6d481b903b5cdb75c9cf9a270bf8f7
parentb9198f3b3a9fc22118e1d40888d8423eac448ad1 (diff)
downloadart-75d4422b08058ba92dfdeebc1bbe1f89d591b721.tar.gz
Implement Pre-reboot Dexopt.
Pre-reboot Dexopt reuses the normal dexopt workflow. The entry point is `ArtManagerLocal.dexoptPackages`. The only differences are: - It appends the ".staged" suffix to the filenames of the output dexopt artifacts and profiles. - It does not clear cur profiles. - It does not delete runtime artifacts. - It never updates the dex use protobuf file. Bug: 311377497 Test: atest ArtServiceTests Test: m test-art-host-gtest-art_artd_tests Change-Id: I7ab98015a85c0a24cc2083a317048dcf548449ea
-rw-r--r--artd/README.md9
-rw-r--r--artd/artd.cc103
-rw-r--r--artd/artd_test.cc228
-rw-r--r--artd/binder/com/android/server/art/ArtifactsPath.aidl5
-rw-r--r--artd/binder/com/android/server/art/IArtd.aidl16
-rw-r--r--artd/binder/com/android/server/art/ProfilePath.aidl12
-rw-r--r--artd/path_utils.cc79
-rw-r--r--artd/path_utils.h57
-rw-r--r--artd/path_utils_test.cc130
-rw-r--r--libartservice/service/java/com/android/server/art/AidlUtils.java63
-rw-r--r--libartservice/service/java/com/android/server/art/ArtFileManager.java14
-rw-r--r--libartservice/service/java/com/android/server/art/ArtManagerLocal.java17
-rw-r--r--libartservice/service/java/com/android/server/art/DexUseManagerLocal.java9
-rw-r--r--libartservice/service/java/com/android/server/art/Dexopter.java34
-rw-r--r--libartservice/service/java/com/android/server/art/PrimaryDexUtils.java10
-rw-r--r--libartservice/service/java/com/android/server/art/PrimaryDexopter.java8
-rw-r--r--libartservice/service/java/com/android/server/art/SecondaryDexopter.java7
-rw-r--r--libartservice/service/javatests/com/android/server/art/ArtManagerLocalTest.java125
-rw-r--r--libartservice/service/javatests/com/android/server/art/DexUseManagerTest.java8
-rw-r--r--libartservice/service/javatests/com/android/server/art/PrimaryDexopterParameterizedTest.java52
-rw-r--r--libartservice/service/javatests/com/android/server/art/PrimaryDexopterTest.java67
-rw-r--r--libartservice/service/javatests/com/android/server/art/PrimaryDexopterTestBase.java1
-rw-r--r--libartservice/service/javatests/com/android/server/art/SecondaryDexopterTest.java20
23 files changed, 803 insertions, 271 deletions
diff --git a/artd/README.md b/artd/README.md
index a2dfc099e9..3a073c7b08 100644
--- a/artd/README.md
+++ b/artd/README.md
@@ -14,3 +14,12 @@ doesn't include options passed to dex2oat and other processes.
- `dalvik.vm.artd-verbose`: Log verbosity of the artd process. The syntax is the
same as the runtime's `-verbose` flag.
+
+### The `--pre-reboot` flag
+
+artd can be run in Pre-reboot mode through the `--pre-reboot` flag. The
+Pre-reboot mode is for generating outputs for Pre-reboot Dexopt. The flag does
+not change the actual behavior, but only affects the service name, the log tag,
+a few return checks, etc. Note that how artd addresses input files and output
+files is solely determined by AIDL arguments and is **not** affected by the
+`--pre-reboot` flag.
diff --git a/artd/artd.cc b/artd/artd.cc
index 04223d2eb4..6154c8207b 100644
--- a/artd/artd.cc
+++ b/artd/artd.cc
@@ -252,7 +252,8 @@ Result<void> PrepareArtifactsDirs(const OutputArtifacts& output_artifacts,
return {};
}
- std::filesystem::path oat_path(OR_RETURN(BuildOatPath(output_artifacts.artifactsPath)));
+ std::filesystem::path oat_path(
+ OR_RETURN(BuildArtifactsPath(output_artifacts.artifactsPath)).oat_path);
std::filesystem::path isa_dir = oat_path.parent_path();
std::filesystem::path oat_dir = isa_dir.parent_path();
DCHECK_EQ(oat_dir.filename(), "oat");
@@ -481,11 +482,33 @@ std::ostream& operator<<(std::ostream& os, const FdLogger& fd_logger) {
} // namespace
+#define RETURN_FATAL_IF_PRE_REBOOT(options) \
+ if (options.is_pre_reboot) { \
+ return Fatal("This method is not supported in Pre-reboot Dexopt mode"); \
+ }
+
#define RETURN_FATAL_IF_NOT_PRE_REBOOT(options) \
if (!options.is_pre_reboot) { \
return Fatal("This method is only supported in Pre-reboot Dexopt mode"); \
}
+#define RETURN_FATAL_IF_ARG_IS_PRE_REBOOT_IMPL(expected, arg, log_name) \
+ { \
+ auto&& __return_fatal_tmp = PreRebootFlag(arg); \
+ if (expected != __return_fatal_tmp) { \
+ return Fatal(ART_FORMAT("Expected flag 'isPreReboot' in argument '{}' to be {}, got {}", \
+ log_name, \
+ expected, \
+ __return_fatal_tmp)); \
+ } \
+ }
+
+#define RETURN_FATAL_IF_PRE_REBOOT_MISMATCH(options, arg, log_name) \
+ RETURN_FATAL_IF_ARG_IS_PRE_REBOOT_IMPL(options.is_pre_reboot, arg, log_name)
+
+#define RETURN_FATAL_IF_ARG_IS_PRE_REBOOT(arg, log_name) \
+ RETURN_FATAL_IF_ARG_IS_PRE_REBOOT_IMPL(false, arg, log_name)
+
Result<void> Restorecon(
const std::string& path,
const std::optional<OutputArtifacts::PermissionSettings::SeContext>& se_context,
@@ -514,12 +537,15 @@ ScopedAStatus Artd::isAlive(bool* _aidl_return) {
}
ScopedAStatus Artd::deleteArtifacts(const ArtifactsPath& in_artifactsPath, int64_t* _aidl_return) {
- std::string oat_path = OR_RETURN_FATAL(BuildOatPath(in_artifactsPath));
+ RETURN_FATAL_IF_PRE_REBOOT(options_);
+ RETURN_FATAL_IF_ARG_IS_PRE_REBOOT(in_artifactsPath, "artifactsPath");
+
+ RawArtifactsPath path = OR_RETURN_FATAL(BuildArtifactsPath(in_artifactsPath));
*_aidl_return = 0;
- *_aidl_return += GetSizeAndDeleteFile(oat_path);
- *_aidl_return += GetSizeAndDeleteFile(OatPathToVdexPath(oat_path));
- *_aidl_return += GetSizeAndDeleteFile(OatPathToArtPath(oat_path));
+ *_aidl_return += GetSizeAndDeleteFile(path.oat_path);
+ *_aidl_return += GetSizeAndDeleteFile(path.vdex_path);
+ *_aidl_return += GetSizeAndDeleteFile(path.art_path);
return ScopedAStatus::ok();
}
@@ -528,6 +554,8 @@ ScopedAStatus Artd::getDexoptStatus(const std::string& in_dexFile,
const std::string& in_instructionSet,
const std::optional<std::string>& in_classLoaderContext,
GetDexoptStatusResult* _aidl_return) {
+ RETURN_FATAL_IF_PRE_REBOOT(options_);
+
Result<OatFileAssistantContext*> ofa_context = GetOatFileAssistantContext();
if (!ofa_context.ok()) {
return NonFatal("Failed to get runtime options: " + ofa_context.error().message());
@@ -569,6 +597,8 @@ ScopedAStatus Artd::getDexoptStatus(const std::string& in_dexFile,
ndk::ScopedAStatus Artd::isProfileUsable(const ProfilePath& in_profile,
const std::string& in_dexFile,
bool* _aidl_return) {
+ RETURN_FATAL_IF_ARG_IS_PRE_REBOOT(in_profile, "profile");
+
std::string profile_path = OR_RETURN_FATAL(BuildProfileOrDmPath(in_profile));
OR_RETURN_FATAL(ValidateDexPath(in_dexFile));
@@ -621,6 +651,7 @@ ndk::ScopedAStatus Artd::CopyAndRewriteProfileImpl(File src,
OutputProfile* dst_aidl,
const std::string& dex_path,
CopyAndRewriteProfileResult* aidl_return) {
+ RETURN_FATAL_IF_PRE_REBOOT_MISMATCH(options_, *dst_aidl, "dst");
std::string dst_path = OR_RETURN_FATAL(BuildFinalProfilePath(dst_aidl->profilePath));
OR_RETURN_FATAL(ValidateDexPath(dex_path));
@@ -678,6 +709,8 @@ ndk::ScopedAStatus Artd::copyAndRewriteProfile(const ProfilePath& in_src,
OutputProfile* in_dst,
const std::string& in_dexFile,
CopyAndRewriteProfileResult* _aidl_return) {
+ RETURN_FATAL_IF_ARG_IS_PRE_REBOOT(in_src, "src");
+
std::string src_path = OR_RETURN_FATAL(BuildProfileOrDmPath(in_src));
Result<std::unique_ptr<File>> src = OpenFileForReading(src_path);
@@ -712,6 +745,7 @@ ndk::ScopedAStatus Artd::copyAndRewriteEmbeddedProfile(OutputProfile* in_dst,
}
ndk::ScopedAStatus Artd::commitTmpProfile(const TmpProfilePath& in_profile) {
+ RETURN_FATAL_IF_PRE_REBOOT_MISMATCH(options_, in_profile, "profile");
std::string tmp_profile_path = OR_RETURN_FATAL(BuildTmpProfilePath(in_profile));
std::string ref_profile_path = OR_RETURN_FATAL(BuildFinalProfilePath(in_profile));
@@ -726,6 +760,8 @@ ndk::ScopedAStatus Artd::commitTmpProfile(const TmpProfilePath& in_profile) {
}
ndk::ScopedAStatus Artd::deleteProfile(const ProfilePath& in_profile) {
+ RETURN_FATAL_IF_ARG_IS_PRE_REBOOT(in_profile, "profile");
+
std::string profile_path = OR_RETURN_FATAL(BuildProfileOrDmPath(in_profile));
std::error_code ec;
@@ -739,6 +775,7 @@ ndk::ScopedAStatus Artd::deleteProfile(const ProfilePath& in_profile) {
ndk::ScopedAStatus Artd::getProfileVisibility(const ProfilePath& in_profile,
FileVisibility* _aidl_return) {
+ RETURN_FATAL_IF_ARG_IS_PRE_REBOOT(in_profile, "profile");
std::string profile_path = OR_RETURN_FATAL(BuildProfileOrDmPath(in_profile));
*_aidl_return = OR_RETURN_NON_FATAL(GetFileVisibility(profile_path));
return ScopedAStatus::ok();
@@ -746,7 +783,8 @@ ndk::ScopedAStatus Artd::getProfileVisibility(const ProfilePath& in_profile,
ndk::ScopedAStatus Artd::getArtifactsVisibility(const ArtifactsPath& in_artifactsPath,
FileVisibility* _aidl_return) {
- std::string oat_path = OR_RETURN_FATAL(BuildOatPath(in_artifactsPath));
+ RETURN_FATAL_IF_ARG_IS_PRE_REBOOT(in_artifactsPath, "artifactsPath");
+ std::string oat_path = OR_RETURN_FATAL(BuildArtifactsPath(in_artifactsPath)).oat_path;
*_aidl_return = OR_RETURN_NON_FATAL(GetFileVisibility(oat_path));
return ScopedAStatus::ok();
}
@@ -773,12 +811,15 @@ ndk::ScopedAStatus Artd::mergeProfiles(const std::vector<ProfilePath>& in_profil
bool* _aidl_return) {
std::vector<std::string> profile_paths;
for (const ProfilePath& profile : in_profiles) {
+ RETURN_FATAL_IF_ARG_IS_PRE_REBOOT(profile, "profiles");
std::string profile_path = OR_RETURN_FATAL(BuildProfileOrDmPath(profile));
if (profile.getTag() == ProfilePath::dexMetadataPath) {
return Fatal(ART_FORMAT("Does not support DM file, got '{}'", profile_path));
}
profile_paths.push_back(std::move(profile_path));
}
+
+ RETURN_FATAL_IF_PRE_REBOOT_MISMATCH(options_, *in_outputProfile, "outputProfile");
std::string output_profile_path =
OR_RETURN_FATAL(BuildFinalProfilePath(in_outputProfile->profilePath));
for (const std::string& dex_file : in_dexFiles) {
@@ -826,6 +867,7 @@ ndk::ScopedAStatus Artd::mergeProfiles(const std::vector<ProfilePath>& in_profil
return Fatal(
"Reference profile must not be set when 'dumpOnly' or 'dumpClassesAndMethods' is set");
}
+ // `in_referenceProfile` can be either a Pre-reboot profile or an ordinary one.
std::string reference_profile_path =
OR_RETURN_FATAL(BuildProfileOrDmPath(*in_referenceProfile));
if (in_referenceProfile->getTag() == ProfilePath::dexMetadataPath) {
@@ -950,10 +992,11 @@ ndk::ScopedAStatus Artd::dexopt(
ArtdDexoptResult* _aidl_return) {
_aidl_return->cancelled = false;
- std::string oat_path = OR_RETURN_FATAL(BuildOatPath(in_outputArtifacts.artifactsPath));
- std::string vdex_path = OatPathToVdexPath(oat_path);
- std::string art_path = OatPathToArtPath(oat_path);
+ RETURN_FATAL_IF_PRE_REBOOT_MISMATCH(options_, in_outputArtifacts, "outputArtifacts");
+ RawArtifactsPath artifacts_path =
+ OR_RETURN_FATAL(BuildArtifactsPath(in_outputArtifacts.artifactsPath));
OR_RETURN_FATAL(ValidateDexPath(in_dexFile));
+ // `in_profile` can be either a Pre-reboot profile or an ordinary one.
std::optional<std::string> profile_path =
in_profile.has_value() ?
std::make_optional(OR_RETURN_FATAL(BuildProfileOrDmPath(in_profile.value()))) :
@@ -1018,12 +1061,13 @@ ndk::ScopedAStatus Artd::dexopt(
}
}
- std::unique_ptr<NewFile> oat_file = OR_RETURN_NON_FATAL(NewFile::Create(oat_path, fs_permission));
- args.Add("--oat-fd=%d", oat_file->Fd()).Add("--oat-location=%s", oat_path);
+ std::unique_ptr<NewFile> oat_file =
+ OR_RETURN_NON_FATAL(NewFile::Create(artifacts_path.oat_path, fs_permission));
+ args.Add("--oat-fd=%d", oat_file->Fd()).Add("--oat-location=%s", artifacts_path.oat_path);
fd_logger.Add(*oat_file);
std::unique_ptr<NewFile> vdex_file =
- OR_RETURN_NON_FATAL(NewFile::Create(vdex_path, fs_permission));
+ OR_RETURN_NON_FATAL(NewFile::Create(artifacts_path.vdex_path, fs_permission));
args.Add("--output-vdex-fd=%d", vdex_file->Fd());
fd_logger.Add(*vdex_file);
@@ -1032,18 +1076,18 @@ ndk::ScopedAStatus Artd::dexopt(
std::unique_ptr<NewFile> art_file = nullptr;
if (in_dexoptOptions.generateAppImage) {
- art_file = OR_RETURN_NON_FATAL(NewFile::Create(art_path, fs_permission));
+ art_file = OR_RETURN_NON_FATAL(NewFile::Create(artifacts_path.art_path, fs_permission));
args.Add("--app-image-fd=%d", art_file->Fd());
args.AddIfNonEmpty("--image-format=%s", props_->GetOrEmpty("dalvik.vm.appimageformat"));
fd_logger.Add(*art_file);
files_to_commit.push_back(art_file.get());
} else {
- files_to_delete.push_back(art_path);
+ files_to_delete.push_back(artifacts_path.art_path);
}
std::unique_ptr<NewFile> swap_file = nullptr;
if (ShouldCreateSwapFileForDexopt()) {
- std::string swap_file_path = ART_FORMAT("{}.swap", oat_path);
+ std::string swap_file_path = ART_FORMAT("{}.swap", artifacts_path.oat_path);
swap_file =
OR_RETURN_NON_FATAL(NewFile::Create(swap_file_path, FsPermission{.uid = -1, .gid = -1}));
args.Add("--swap-fd=%d", swap_file->Fd());
@@ -1070,6 +1114,7 @@ ndk::ScopedAStatus Artd::dexopt(
std::unique_ptr<File> input_vdex_file = nullptr;
if (in_inputVdex.has_value()) {
+ RETURN_FATAL_IF_ARG_IS_PRE_REBOOT(in_inputVdex.value(), "inputVdex");
std::string input_vdex_path = OR_RETURN_FATAL(BuildVdexPath(in_inputVdex.value()));
input_vdex_file = OR_RETURN_NON_FATAL(OpenFileForReading(input_vdex_path));
args.Add("--input-vdex-fd=%d", input_vdex_file->Fd());
@@ -1204,17 +1249,21 @@ ScopedAStatus Artd::cleanup(const std::vector<ProfilePath>& in_profilesToKeep,
const std::vector<VdexPath>& in_vdexFilesToKeep,
const std::vector<RuntimeArtifactsPath>& in_runtimeArtifactsToKeep,
int64_t* _aidl_return) {
+ RETURN_FATAL_IF_PRE_REBOOT(options_);
std::unordered_set<std::string> files_to_keep;
for (const ProfilePath& profile : in_profilesToKeep) {
+ RETURN_FATAL_IF_ARG_IS_PRE_REBOOT(profile, "profilesToKeep");
files_to_keep.insert(OR_RETURN_FATAL(BuildProfileOrDmPath(profile)));
}
for (const ArtifactsPath& artifacts : in_artifactsToKeep) {
- std::string oat_path = OR_RETURN_FATAL(BuildOatPath(artifacts));
- files_to_keep.insert(OatPathToVdexPath(oat_path));
- files_to_keep.insert(OatPathToArtPath(oat_path));
- files_to_keep.insert(std::move(oat_path));
+ RETURN_FATAL_IF_ARG_IS_PRE_REBOOT(artifacts, "artifactsToKeep");
+ RawArtifactsPath path = OR_RETURN_FATAL(BuildArtifactsPath(artifacts));
+ files_to_keep.insert(std::move(path.oat_path));
+ files_to_keep.insert(std::move(path.vdex_path));
+ files_to_keep.insert(std::move(path.art_path));
}
for (const VdexPath& vdex : in_vdexFilesToKeep) {
+ RETURN_FATAL_IF_ARG_IS_PRE_REBOOT(vdex, "vdexFilesToKeep");
files_to_keep.insert(OR_RETURN_FATAL(BuildVdexPath(vdex)));
}
std::string android_data = OR_RETURN_NON_FATAL(GetAndroidDataOrError());
@@ -1268,6 +1317,7 @@ ScopedAStatus Artd::isInDalvikCache(const std::string& in_dexFile, bool* _aidl_r
ScopedAStatus Artd::deleteRuntimeArtifacts(const RuntimeArtifactsPath& in_runtimeArtifactsPath,
int64_t* _aidl_return) {
+ RETURN_FATAL_IF_PRE_REBOOT(options_);
OR_RETURN_FATAL(ValidateRuntimeArtifactsPath(in_runtimeArtifactsPath));
*_aidl_return = 0;
std::string android_data = OR_LOG_AND_RETURN_OK(GetAndroidDataOrError());
@@ -1280,15 +1330,19 @@ ScopedAStatus Artd::deleteRuntimeArtifacts(const RuntimeArtifactsPath& in_runtim
}
ScopedAStatus Artd::getArtifactsSize(const ArtifactsPath& in_artifactsPath, int64_t* _aidl_return) {
- std::string oat_path = OR_RETURN_FATAL(BuildOatPath(in_artifactsPath));
+ RETURN_FATAL_IF_PRE_REBOOT(options_);
+ RETURN_FATAL_IF_ARG_IS_PRE_REBOOT(in_artifactsPath, "artifactsPath");
+ RawArtifactsPath path = OR_RETURN_FATAL(BuildArtifactsPath(in_artifactsPath));
*_aidl_return = 0;
- *_aidl_return += GetSize(oat_path).value_or(0);
- *_aidl_return += GetSize(OatPathToVdexPath(oat_path)).value_or(0);
- *_aidl_return += GetSize(OatPathToArtPath(oat_path)).value_or(0);
+ *_aidl_return += GetSize(path.oat_path).value_or(0);
+ *_aidl_return += GetSize(path.vdex_path).value_or(0);
+ *_aidl_return += GetSize(path.art_path).value_or(0);
return ScopedAStatus::ok();
}
ScopedAStatus Artd::getVdexFileSize(const VdexPath& in_vdexPath, int64_t* _aidl_return) {
+ RETURN_FATAL_IF_PRE_REBOOT(options_);
+ RETURN_FATAL_IF_ARG_IS_PRE_REBOOT(in_vdexPath, "vdexPath");
std::string vdex_path = OR_RETURN_FATAL(BuildVdexPath(in_vdexPath));
*_aidl_return = GetSize(vdex_path).value_or(0);
return ScopedAStatus::ok();
@@ -1296,6 +1350,7 @@ ScopedAStatus Artd::getVdexFileSize(const VdexPath& in_vdexPath, int64_t* _aidl_
ScopedAStatus Artd::getRuntimeArtifactsSize(const RuntimeArtifactsPath& in_runtimeArtifactsPath,
int64_t* _aidl_return) {
+ RETURN_FATAL_IF_PRE_REBOOT(options_);
OR_RETURN_FATAL(ValidateRuntimeArtifactsPath(in_runtimeArtifactsPath));
*_aidl_return = 0;
std::string android_data = OR_LOG_AND_RETURN_OK(GetAndroidDataOrError());
@@ -1308,6 +1363,8 @@ ScopedAStatus Artd::getRuntimeArtifactsSize(const RuntimeArtifactsPath& in_runti
}
ScopedAStatus Artd::getProfileSize(const ProfilePath& in_profile, int64_t* _aidl_return) {
+ RETURN_FATAL_IF_PRE_REBOOT(options_);
+ RETURN_FATAL_IF_ARG_IS_PRE_REBOOT(in_profile, "profile");
std::string profile_path = OR_RETURN_FATAL(BuildProfileOrDmPath(in_profile));
*_aidl_return = GetSize(profile_path).value_or(0);
return ScopedAStatus::ok();
diff --git a/artd/artd_test.cc b/artd/artd_test.cc
index 7c3f1bc803..fccf091464 100644
--- a/artd/artd_test.cc
+++ b/artd/artd_test.cc
@@ -129,6 +129,7 @@ using ::testing::WithArg;
using PrimaryCurProfilePath = ProfilePath::PrimaryCurProfilePath;
using PrimaryRefProfilePath = ProfilePath::PrimaryRefProfilePath;
using TmpProfilePath = ProfilePath::TmpProfilePath;
+using WritableProfilePath = ProfilePath::WritableProfilePath;
using std::literals::operator""s; // NOLINT
@@ -392,7 +393,8 @@ class ArtdTest : public CommonArtTest {
compiler_filter_ = "speed";
tmp_profile_path_ =
TmpProfilePath{.finalPath = PrimaryRefProfilePath{.packageName = "com.android.foo",
- .profileName = "primary"},
+ .profileName = "primary",
+ .isPreReboot = false},
.id = "12345"};
profile_path_ = tmp_profile_path_;
vdex_path_ = artifacts_path_;
@@ -447,7 +449,7 @@ class ArtdTest : public CommonArtTest {
std::pair<std::conditional_t<kExpectOk, CopyAndRewriteProfileResult, ndk::ScopedAStatus>,
OutputProfile>>;
- // Runs `copyAndRewriteProfile` with `tmp_profile_path_` and `dex_file_`.
+ // Runs `copyAndRewriteProfile` with `profile_path_` and `dex_file_`.
template <bool kExpectOk = true>
RunCopyAndRewriteProfileResult<kExpectOk> RunCopyAndRewriteProfile() {
OutputProfile dst{.profilePath = tmp_profile_path_,
@@ -457,7 +459,7 @@ class ArtdTest : public CommonArtTest {
CopyAndRewriteProfileResult result;
ndk::ScopedAStatus status =
- artd_->copyAndRewriteProfile(tmp_profile_path_, &dst, dex_file_, &result);
+ artd_->copyAndRewriteProfile(profile_path_.value(), &dst, dex_file_, &result);
if constexpr (kExpectOk) {
if (!status.isOk()) {
return Error() << status.getMessage();
@@ -568,10 +570,10 @@ class ArtdTest : public CommonArtTest {
}
// Files to be replaced.
- std::string oat_path = OR_FATAL(BuildOatPath(artifacts_path_));
- CreateFile(oat_path, "old_oat");
- CreateFile(OatPathToVdexPath(oat_path), "old_vdex");
- CreateFile(OatPathToArtPath(oat_path), "old_art");
+ RawArtifactsPath artifacts_path = OR_FATAL(BuildArtifactsPath(artifacts_path_));
+ CreateFile(artifacts_path.oat_path, "old_oat");
+ CreateFile(artifacts_path.vdex_path, "old_vdex");
+ CreateFile(artifacts_path.art_path, "old_art");
}
};
@@ -1389,7 +1391,7 @@ TEST_F(ArtdTest, isProfileUsableFailed) {
}
TEST_F(ArtdTest, copyAndRewriteProfileSuccess) {
- std::string src_file = OR_FATAL(BuildTmpProfilePath(tmp_profile_path_));
+ std::string src_file = OR_FATAL(BuildProfileOrDmPath(profile_path_.value()));
CreateFile(src_file, "valid_profile");
CreateFile(dex_file_);
@@ -1421,7 +1423,7 @@ TEST_F(ArtdTest, copyAndRewriteProfileSuccess) {
// The input is a plain profile file in the wrong format.
TEST_F(ArtdTest, copyAndRewriteProfileBadProfileWrongFormat) {
- std::string src_file = OR_FATAL(BuildTmpProfilePath(tmp_profile_path_));
+ std::string src_file = OR_FATAL(BuildProfileOrDmPath(profile_path_.value()));
CreateFile(src_file, "wrong_format");
CreateFile(dex_file_);
@@ -1440,7 +1442,7 @@ TEST_F(ArtdTest, copyAndRewriteProfileBadProfileWrongFormat) {
// The input is a plain profile file that doesn't match the APK.
TEST_F(ArtdTest, copyAndRewriteProfileBadProfileNoMatch) {
- std::string src_file = OR_FATAL(BuildTmpProfilePath(tmp_profile_path_));
+ std::string src_file = OR_FATAL(BuildProfileOrDmPath(profile_path_.value()));
CreateFile(src_file, "no_match");
CreateFile(dex_file_);
@@ -1458,7 +1460,7 @@ TEST_F(ArtdTest, copyAndRewriteProfileBadProfileNoMatch) {
// The input is a plain profile file that is empty.
TEST_F(ArtdTest, copyAndRewriteProfileNoProfileEmpty) {
- std::string src_file = OR_FATAL(BuildTmpProfilePath(tmp_profile_path_));
+ std::string src_file = OR_FATAL(BuildProfileOrDmPath(profile_path_.value()));
CreateFile(src_file, "");
CreateFile(dex_file_);
@@ -1486,7 +1488,7 @@ TEST_F(ArtdTest, copyAndRewriteProfileNoProfileNoFile) {
// The input is a dm file with a profile entry in the wrong format.
TEST_F(ArtdTest, copyAndRewriteProfileNoProfileDmWrongFormat) {
- std::string src_file = OR_FATAL(BuildTmpProfilePath(tmp_profile_path_));
+ std::string src_file = OR_FATAL(BuildProfileOrDmPath(profile_path_.value()));
CreateZipWithSingleEntry(src_file, "primary.prof", "wrong_format");
CreateFile(dex_file_);
@@ -1505,7 +1507,7 @@ TEST_F(ArtdTest, copyAndRewriteProfileNoProfileDmWrongFormat) {
// The input is a dm file with a profile entry that doesn't match the APK.
TEST_F(ArtdTest, copyAndRewriteProfileNoProfileDmNoMatch) {
- std::string src_file = OR_FATAL(BuildTmpProfilePath(tmp_profile_path_));
+ std::string src_file = OR_FATAL(BuildProfileOrDmPath(profile_path_.value()));
CreateZipWithSingleEntry(src_file, "primary.prof", "no_match");
CreateFile(dex_file_);
@@ -1523,7 +1525,7 @@ TEST_F(ArtdTest, copyAndRewriteProfileNoProfileDmNoMatch) {
// The input is a dm file with a profile entry that is empty.
TEST_F(ArtdTest, copyAndRewriteProfileNoProfileDmEmpty) {
- std::string src_file = OR_FATAL(BuildTmpProfilePath(tmp_profile_path_));
+ std::string src_file = OR_FATAL(BuildProfileOrDmPath(profile_path_.value()));
CreateZipWithSingleEntry(src_file, "primary.prof");
CreateFile(dex_file_);
@@ -1540,7 +1542,7 @@ TEST_F(ArtdTest, copyAndRewriteProfileNoProfileDmEmpty) {
// The input is a dm file without a profile entry.
TEST_F(ArtdTest, copyAndRewriteProfileNoProfileDmNoEntry) {
- std::string src_file = OR_FATAL(BuildTmpProfilePath(tmp_profile_path_));
+ std::string src_file = OR_FATAL(BuildProfileOrDmPath(profile_path_.value()));
CreateZipWithSingleEntry(src_file, "primary.vdex");
CreateFile(dex_file_);
@@ -1556,7 +1558,7 @@ TEST_F(ArtdTest, copyAndRewriteProfileNoProfileDmNoEntry) {
}
TEST_F(ArtdTest, copyAndRewriteProfileException) {
- std::string src_file = OR_FATAL(BuildTmpProfilePath(tmp_profile_path_));
+ std::string src_file = OR_FATAL(BuildProfileOrDmPath(profile_path_.value()));
CreateFile(src_file, "valid_profile");
CreateFile(dex_file_);
@@ -1780,13 +1782,15 @@ TEST_F(ArtdGetVisibilityTest, getProfileVisibilityPermissionDenied) {
}
TEST_F(ArtdGetVisibilityTest, getArtifactsVisibilityOtherReadable) {
- TestGetVisibilityOtherReadable(
- &Artd::getArtifactsVisibility, artifacts_path_, OR_FATAL(BuildOatPath(artifacts_path_)));
+ TestGetVisibilityOtherReadable(&Artd::getArtifactsVisibility,
+ artifacts_path_,
+ OR_FATAL(BuildArtifactsPath(artifacts_path_)).oat_path);
}
TEST_F(ArtdGetVisibilityTest, getArtifactsVisibilityNotOtherReadable) {
- TestGetVisibilityNotOtherReadable(
- &Artd::getArtifactsVisibility, artifacts_path_, OR_FATAL(BuildOatPath(artifacts_path_)));
+ TestGetVisibilityNotOtherReadable(&Artd::getArtifactsVisibility,
+ artifacts_path_,
+ OR_FATAL(BuildArtifactsPath(artifacts_path_)).oat_path);
}
TEST_F(ArtdGetVisibilityTest, getArtifactsVisibilityNotFound) {
@@ -1794,8 +1798,9 @@ TEST_F(ArtdGetVisibilityTest, getArtifactsVisibilityNotFound) {
}
TEST_F(ArtdGetVisibilityTest, getArtifactsVisibilityPermissionDenied) {
- TestGetVisibilityPermissionDenied(
- &Artd::getArtifactsVisibility, artifacts_path_, OR_FATAL(BuildOatPath(artifacts_path_)));
+ TestGetVisibilityPermissionDenied(&Artd::getArtifactsVisibility,
+ artifacts_path_,
+ OR_FATAL(BuildArtifactsPath(artifacts_path_)).oat_path);
}
TEST_F(ArtdGetVisibilityTest, getDexFileVisibilityOtherReadable) {
@@ -1837,8 +1842,7 @@ TEST_F(ArtdGetVisibilityTest, getDmFileVisibilityPermissionDenied) {
}
TEST_F(ArtdTest, mergeProfiles) {
- const TmpProfilePath& reference_profile_path = tmp_profile_path_;
- std::string reference_profile_file = OR_FATAL(BuildTmpProfilePath(reference_profile_path));
+ std::string reference_profile_file = OR_FATAL(BuildProfileOrDmPath(profile_path_.value()));
CreateFile(reference_profile_file, "abc");
// Doesn't exist.
@@ -1851,7 +1855,7 @@ TEST_F(ArtdTest, mergeProfiles) {
std::string profile_1_file = OR_FATAL(BuildPrimaryCurProfilePath(profile_1_path));
CreateFile(profile_1_file, "def");
- OutputProfile output_profile{.profilePath = reference_profile_path,
+ OutputProfile output_profile{.profilePath = tmp_profile_path_,
.fsPermission = FsPermission{.uid = -1, .gid = -1}};
output_profile.profilePath.id = "";
output_profile.profilePath.tmpPath = "";
@@ -1884,7 +1888,7 @@ TEST_F(ArtdTest, mergeProfiles) {
bool result;
EXPECT_TRUE(artd_
->mergeProfiles({profile_0_path, profile_1_path},
- reference_profile_path,
+ profile_path_,
&output_profile,
{dex_file_1, dex_file_2},
/*in_options=*/{},
@@ -1939,10 +1943,6 @@ TEST_F(ArtdTest, mergeProfilesEmptyReferenceProfile) {
}
TEST_F(ArtdTest, mergeProfilesProfilesDontExist) {
- const TmpProfilePath& reference_profile_path = tmp_profile_path_;
- std::string reference_profile_file = OR_FATAL(BuildTmpProfilePath(reference_profile_path));
- CreateFile(reference_profile_file, "abc");
-
// Doesn't exist.
PrimaryCurProfilePath profile_0_path{
.userId = 0, .packageName = "com.android.foo", .profileName = "primary"};
@@ -1953,7 +1953,7 @@ TEST_F(ArtdTest, mergeProfilesProfilesDontExist) {
.userId = 1, .packageName = "com.android.foo", .profileName = "primary"};
std::string profile_1_file = OR_FATAL(BuildPrimaryCurProfilePath(profile_1_path));
- OutputProfile output_profile{.profilePath = reference_profile_path,
+ OutputProfile output_profile{.profilePath = tmp_profile_path_,
.fsPermission = FsPermission{.uid = -1, .gid = -1}};
output_profile.profilePath.id = "";
output_profile.profilePath.tmpPath = "";
@@ -1965,7 +1965,7 @@ TEST_F(ArtdTest, mergeProfilesProfilesDontExist) {
bool result;
EXPECT_TRUE(artd_
->mergeProfiles({profile_0_path},
- std::nullopt,
+ /*in_referenceProfile=*/std::nullopt,
&output_profile,
{dex_file_},
/*in_options=*/{},
@@ -2479,6 +2479,9 @@ class ArtdPreRebootTest : public ArtdTest {
)";
ASSERT_TRUE(WriteStringToFile(ART_FORMAT(kInitEnvironRcTmpl, art_root_, android_data_),
init_environ_rc_path_));
+
+ tmp_profile_path_.finalPath.get<WritableProfilePath::forPrimary>().isPreReboot = true;
+ output_artifacts_.artifactsPath.isPreReboot = true;
}
std::string pre_reboot_tmp_dir_;
@@ -2599,6 +2602,167 @@ TEST_F(ArtdPreRebootTest, preRebootInitNoRetry) {
"preRebootInit must not be concurrently called or retried after failure");
}
+TEST_F(ArtdPreRebootTest, dexopt) {
+ std::string profile_file = OR_FATAL(BuildProfileOrDmPath(profile_path_.value()));
+
+ dexopt_options_.generateAppImage = true;
+
+ EXPECT_CALL(
+ *mock_exec_utils_,
+ DoExecAndReturnCode(
+ WhenSplitBy("--", _, Contains(Flag("--profile-file-fd=", FdOf(profile_file)))), _, _))
+ .WillOnce(DoAll(WithArg<0>(WriteToFdFlag("--oat-fd=", "oat")),
+ WithArg<0>(WriteToFdFlag("--output-vdex-fd=", "vdex")),
+ WithArg<0>(WriteToFdFlag("--app-image-fd=", "art")),
+ Return(0)));
+ RunDexopt();
+
+ CheckContent(scratch_path_ + "/a/oat/arm64/b.odex.staged", "oat");
+ CheckContent(scratch_path_ + "/a/oat/arm64/b.vdex.staged", "vdex");
+ CheckContent(scratch_path_ + "/a/oat/arm64/b.art.staged", "art");
+}
+
+TEST_F(ArtdPreRebootTest, dexoptPreRebootProfile) {
+ profile_path_->get<ProfilePath::tmpProfilePath>()
+ .finalPath.get<WritableProfilePath::forPrimary>()
+ .isPreReboot = true;
+ std::string profile_file = OR_FATAL(BuildProfileOrDmPath(profile_path_.value()));
+
+ dexopt_options_.generateAppImage = true;
+
+ EXPECT_CALL(
+ *mock_exec_utils_,
+ DoExecAndReturnCode(
+ WhenSplitBy("--", _, Contains(Flag("--profile-file-fd=", FdOf(profile_file)))), _, _))
+ .WillOnce(DoAll(WithArg<0>(WriteToFdFlag("--oat-fd=", "oat")),
+ WithArg<0>(WriteToFdFlag("--output-vdex-fd=", "vdex")),
+ WithArg<0>(WriteToFdFlag("--app-image-fd=", "art")),
+ Return(0)));
+ RunDexopt();
+
+ CheckContent(scratch_path_ + "/a/oat/arm64/b.odex.staged", "oat");
+ CheckContent(scratch_path_ + "/a/oat/arm64/b.vdex.staged", "vdex");
+ CheckContent(scratch_path_ + "/a/oat/arm64/b.art.staged", "art");
+}
+
+TEST_F(ArtdPreRebootTest, copyAndRewriteProfile) {
+ std::string src_file = OR_FATAL(BuildProfileOrDmPath(profile_path_.value()));
+ CreateFile(src_file, "valid_profile");
+
+ CreateFile(dex_file_);
+
+ EXPECT_CALL(*mock_exec_utils_, DoExecAndReturnCode)
+ .WillOnce(DoAll(WithArg<0>(WriteToFdFlag("--reference-profile-file-fd=", "def")),
+ Return(ProfmanResult::kCopyAndUpdateSuccess)));
+
+ auto [result, dst] = OR_FAIL(RunCopyAndRewriteProfile());
+
+ EXPECT_EQ(result.status, CopyAndRewriteProfileResult::Status::SUCCESS);
+ EXPECT_THAT(dst.profilePath.tmpPath, ContainsRegex(R"re(/primary\.prof\.staged\.\w+\.tmp$)re"));
+ CheckContent(dst.profilePath.tmpPath, "def");
+}
+
+TEST_F(ArtdPreRebootTest, copyAndRewriteEmbeddedProfile) {
+ CreateZipWithSingleEntry(dex_file_, "assets/art-profile/baseline.prof", "valid_profile");
+
+ EXPECT_CALL(*mock_exec_utils_, DoExecAndReturnCode)
+ .WillOnce(DoAll(WithArg<0>(WriteToFdFlag("--reference-profile-file-fd=", "def")),
+ Return(ProfmanResult::kCopyAndUpdateSuccess)));
+
+ auto [result, dst] = OR_FAIL(RunCopyAndRewriteEmbeddedProfile());
+
+ EXPECT_EQ(result.status, CopyAndRewriteProfileResult::Status::SUCCESS);
+ EXPECT_THAT(dst.profilePath.tmpPath, ContainsRegex(R"re(/primary\.prof\.staged\.\w+\.tmp$)re"));
+ CheckContent(dst.profilePath.tmpPath, "def");
+}
+
+TEST_F(ArtdPreRebootTest, mergeProfiles) {
+ std::string reference_profile_file = OR_FATAL(BuildProfileOrDmPath(profile_path_.value()));
+ CreateFile(reference_profile_file, "abc");
+
+ PrimaryCurProfilePath profile_1_path{
+ .userId = 1, .packageName = "com.android.foo", .profileName = "primary"};
+ std::string profile_1_file = OR_FATAL(BuildPrimaryCurProfilePath(profile_1_path));
+ CreateFile(profile_1_file, "def");
+
+ OutputProfile output_profile{.profilePath = tmp_profile_path_,
+ .fsPermission = FsPermission{.uid = -1, .gid = -1}};
+ output_profile.profilePath.id = "";
+ output_profile.profilePath.tmpPath = "";
+
+ std::string dex_file_1 = scratch_path_ + "/a/b.apk";
+ CreateFile(dex_file_1);
+
+ EXPECT_CALL(
+ *mock_exec_utils_,
+ DoExecAndReturnCode(
+ WhenSplitBy("--",
+ _,
+ AllOf(Contains(Flag("--reference-profile-file-fd=", FdHasContent("abc"))),
+ Contains(Flag("--profile-file-fd=", FdHasContent("def"))))),
+ _,
+ _))
+ .WillOnce(DoAll(WithArg<0>(ClearAndWriteToFdFlag("--reference-profile-file-fd=", "merged")),
+ Return(ProfmanResult::kCompile)));
+
+ bool result;
+ ASSERT_STATUS_OK(artd_->mergeProfiles({profile_1_path},
+ profile_path_,
+ &output_profile,
+ {dex_file_1},
+ /*in_options=*/{},
+ &result));
+ EXPECT_TRUE(result);
+ EXPECT_THAT(output_profile.profilePath.tmpPath,
+ ContainsRegex(R"re(/primary\.prof\.staged\.\w+\.tmp$)re"));
+ CheckContent(output_profile.profilePath.tmpPath, "merged");
+}
+
+TEST_F(ArtdPreRebootTest, mergeProfilesPreRebootReference) {
+ profile_path_->get<ProfilePath::tmpProfilePath>()
+ .finalPath.get<WritableProfilePath::forPrimary>()
+ .isPreReboot = true;
+ std::string reference_profile_file = OR_FATAL(BuildProfileOrDmPath(profile_path_.value()));
+ CreateFile(reference_profile_file, "abc");
+
+ PrimaryCurProfilePath profile_1_path{
+ .userId = 1, .packageName = "com.android.foo", .profileName = "primary"};
+ std::string profile_1_file = OR_FATAL(BuildPrimaryCurProfilePath(profile_1_path));
+ CreateFile(profile_1_file, "def");
+
+ OutputProfile output_profile{.profilePath = tmp_profile_path_,
+ .fsPermission = FsPermission{.uid = -1, .gid = -1}};
+ output_profile.profilePath.id = "";
+ output_profile.profilePath.tmpPath = "";
+
+ std::string dex_file_1 = scratch_path_ + "/a/b.apk";
+ CreateFile(dex_file_1);
+
+ EXPECT_CALL(
+ *mock_exec_utils_,
+ DoExecAndReturnCode(
+ WhenSplitBy("--",
+ _,
+ AllOf(Contains(Flag("--reference-profile-file-fd=", FdHasContent("abc"))),
+ Contains(Flag("--profile-file-fd=", FdHasContent("def"))))),
+ _,
+ _))
+ .WillOnce(DoAll(WithArg<0>(ClearAndWriteToFdFlag("--reference-profile-file-fd=", "merged")),
+ Return(ProfmanResult::kCompile)));
+
+ bool result;
+ ASSERT_STATUS_OK(artd_->mergeProfiles({profile_1_path},
+ profile_path_,
+ &output_profile,
+ {dex_file_1},
+ /*in_options=*/{},
+ &result));
+ EXPECT_TRUE(result);
+ EXPECT_THAT(output_profile.profilePath.tmpPath,
+ ContainsRegex(R"re(/primary\.prof\.staged\.\w+\.tmp$)re"));
+ CheckContent(output_profile.profilePath.tmpPath, "merged");
+}
+
} // namespace
} // namespace artd
} // namespace art
diff --git a/artd/binder/com/android/server/art/ArtifactsPath.aidl b/artd/binder/com/android/server/art/ArtifactsPath.aidl
index 3122f0f6b9..e1b1906263 100644
--- a/artd/binder/com/android/server/art/ArtifactsPath.aidl
+++ b/artd/binder/com/android/server/art/ArtifactsPath.aidl
@@ -28,4 +28,9 @@ parcelable ArtifactsPath {
@utf8InCpp String isa;
/** Whether the dexopt artifacts are in the dalvik-cache folder. */
boolean isInDalvikCache;
+ /**
+ * Whether the dexopt artifacts are for Pre-reboot Dexopt. For now, this is always `false` for
+ * inputs because we never take Pre-reboot artifacts as inputs.
+ */
+ boolean isPreReboot;
}
diff --git a/artd/binder/com/android/server/art/IArtd.aidl b/artd/binder/com/android/server/art/IArtd.aidl
index 4273d85515..7f0bc5690c 100644
--- a/artd/binder/com/android/server/art/IArtd.aidl
+++ b/artd/binder/com/android/server/art/IArtd.aidl
@@ -27,6 +27,8 @@ interface IArtd {
* Note that this method doesn't delete runtime artifacts. To delete them, call
* `deleteRuntimeArtifacts`.
*
+ * Not supported in Pre-reboot Dexopt mode.
+ *
* Throws fatal errors. Logs and ignores non-fatal errors.
*/
long deleteArtifacts(in com.android.server.art.ArtifactsPath artifactsPath);
@@ -34,6 +36,8 @@ interface IArtd {
/**
* Returns the dexopt status of a dex file.
*
+ * Not supported in Pre-reboot Dexopt mode.
+ *
* Throws fatal and non-fatal errors.
*/
com.android.server.art.GetDexoptStatusResult getDexoptStatus(
@@ -177,6 +181,8 @@ interface IArtd {
* kept. For each entry in `vdexFilesToKeep`, only the VDEX file will be kept. Note that VDEX
* files included in `artifactsToKeep` don't have to be listed in `vdexFilesToKeep`.
*
+ * Not supported in Pre-reboot Dexopt mode.
+ *
* Throws fatal errors. Logs and ignores non-fatal errors.
*/
long cleanup(in List<com.android.server.art.ProfilePath> profilesToKeep,
@@ -195,6 +201,8 @@ interface IArtd {
/**
* Deletes runtime artifacts and returns the released space, in bytes.
*
+ * Not supported in Pre-reboot Dexopt mode.
+ *
* Throws fatal errors. Logs and ignores non-fatal errors.
*/
long deleteRuntimeArtifacts(
@@ -204,6 +212,8 @@ interface IArtd {
* Returns the size of the dexopt artifacts, in bytes, or 0 if they don't exist or a non-fatal
* error occurred.
*
+ * Not supported in Pre-reboot Dexopt mode.
+ *
* Throws fatal errors. Logs and ignores non-fatal errors.
*/
long getArtifactsSize(in com.android.server.art.ArtifactsPath artifactsPath);
@@ -212,6 +222,8 @@ interface IArtd {
* Returns the size of the vdex file, in bytes, or 0 if it doesn't exist or a non-fatal error
* occurred.
*
+ * Not supported in Pre-reboot Dexopt mode.
+ *
* Throws fatal errors. Logs and ignores non-fatal errors.
*/
long getVdexFileSize(in com.android.server.art.VdexPath vdexPath);
@@ -220,6 +232,8 @@ interface IArtd {
* Returns the size of the runtime artifacts, in bytes, or 0 if they don't exist or a non-fatal
* error occurred.
*
+ * Not supported in Pre-reboot Dexopt mode.
+ *
* Throws fatal errors. Logs and ignores non-fatal errors.
*/
long getRuntimeArtifactsSize(
@@ -231,6 +245,8 @@ interface IArtd {
*
* Operates on the whole DM file if given one.
*
+ * Not supported in Pre-reboot Dexopt mode.
+ *
* Throws fatal errors. Logs and ignores non-fatal errors.
*/
long getProfileSize(in com.android.server.art.ProfilePath profile);
diff --git a/artd/binder/com/android/server/art/ProfilePath.aidl b/artd/binder/com/android/server/art/ProfilePath.aidl
index 43df531d89..d0bbcf2be0 100644
--- a/artd/binder/com/android/server/art/ProfilePath.aidl
+++ b/artd/binder/com/android/server/art/ProfilePath.aidl
@@ -38,6 +38,12 @@ union ProfilePath {
@utf8InCpp String packageName;
/** The stem of the profile file */
@utf8InCpp String profileName;
+ /**
+ * Whether the profile is for Pre-reboot Dexopt. For now, this is `false` for inputs, unless
+ * the data structure refers to a temporary profile, as an argument of `mergeProfiles` or
+ * `dexopt`, in the Pre-reboot Dexopt mode.
+ */
+ boolean isPreReboot;
}
/**
@@ -70,6 +76,12 @@ union ProfilePath {
* `{/data,/mnt/expand/<volume-uuid>}/{user,user_de}/<user-id>/<package-name>/...`.
*/
@utf8InCpp String dexPath;
+ /**
+ * Whether the profile is for Pre-reboot Dexopt. For now, this is `false` for inputs, unless
+ * the data structure refers to a temporary profile, as an argument of `mergeProfiles` or
+ * `dexopt`, in the Pre-reboot Dexopt mode.
+ */
+ boolean isPreReboot;
}
/** Represents a current profile of a secondary dex file. */
diff --git a/artd/path_utils.cc b/artd/path_utils.cc
index 1be75b9358..d3eb6d4dfe 100644
--- a/artd/path_utils.cc
+++ b/artd/path_utils.cc
@@ -39,6 +39,8 @@ namespace {
using ::aidl::com::android::server::art::ArtifactsPath;
using ::aidl::com::android::server::art::DexMetadataPath;
+using ::aidl::com::android::server::art::OutputArtifacts;
+using ::aidl::com::android::server::art::OutputProfile;
using ::aidl::com::android::server::art::ProfilePath;
using ::aidl::com::android::server::art::RuntimeArtifactsPath;
using ::aidl::com::android::server::art::VdexPath;
@@ -56,6 +58,8 @@ using SecondaryRefProfilePath = ProfilePath::SecondaryRefProfilePath;
using TmpProfilePath = ProfilePath::TmpProfilePath;
using WritableProfilePath = ProfilePath::WritableProfilePath;
+constexpr const char* kPreRebootSuffix = ".staged";
+
// Only to be changed for testing.
std::string_view gListRootDir = "/";
@@ -153,7 +157,7 @@ Result<std::string> BuildArtBinPath(const std::string& binary_name) {
return ART_FORMAT("{}/bin/{}", OR_RETURN(GetArtRootOrError()), binary_name);
}
-Result<std::string> BuildOatPath(const ArtifactsPath& artifacts_path) {
+Result<RawArtifactsPath> BuildArtifactsPath(const ArtifactsPath& artifacts_path) {
OR_RETURN(ValidateDexPath(artifacts_path.dexPath));
InstructionSet isa = GetInstructionSetFromString(artifacts_path.isa.c_str());
@@ -162,31 +166,44 @@ Result<std::string> BuildOatPath(const ArtifactsPath& artifacts_path) {
}
std::string error_msg;
- std::string path;
+ RawArtifactsPath path;
if (artifacts_path.isInDalvikCache) {
// Apps' OAT files are never in ART APEX data.
- if (!OatFileAssistant::DexLocationToOatFilename(
- artifacts_path.dexPath, isa, /*deny_art_apex_data_files=*/true, &path, &error_msg)) {
+ if (!OatFileAssistant::DexLocationToOatFilename(artifacts_path.dexPath,
+ isa,
+ /*deny_art_apex_data_files=*/true,
+ &path.oat_path,
+ &error_msg)) {
return Error() << error_msg;
}
- return path;
} else {
if (!OatFileAssistant::DexLocationToOdexFilename(
- artifacts_path.dexPath, isa, &path, &error_msg)) {
+ artifacts_path.dexPath, isa, &path.oat_path, &error_msg)) {
return Error() << error_msg;
}
- return path;
}
+
+ path.vdex_path = ReplaceFileExtension(path.oat_path, "vdex");
+ path.art_path = ReplaceFileExtension(path.oat_path, "art");
+
+ if (artifacts_path.isPreReboot) {
+ path.oat_path += kPreRebootSuffix;
+ path.vdex_path += kPreRebootSuffix;
+ path.art_path += kPreRebootSuffix;
+ }
+
+ return path;
}
Result<std::string> BuildPrimaryRefProfilePath(
const PrimaryRefProfilePath& primary_ref_profile_path) {
OR_RETURN(ValidatePathElement(primary_ref_profile_path.packageName, "packageName"));
OR_RETURN(ValidatePathElementSubstring(primary_ref_profile_path.profileName, "profileName"));
- return ART_FORMAT("{}/misc/profiles/ref/{}/{}.prof",
+ return ART_FORMAT("{}/misc/profiles/ref/{}/{}.prof{}",
OR_RETURN(GetAndroidDataOrError()),
primary_ref_profile_path.packageName,
- primary_ref_profile_path.profileName);
+ primary_ref_profile_path.profileName,
+ primary_ref_profile_path.isPreReboot ? kPreRebootSuffix : "");
}
Result<std::string> BuildPrebuiltProfilePath(const PrebuiltProfilePath& prebuilt_profile_path) {
@@ -209,8 +226,10 @@ Result<std::string> BuildSecondaryRefProfilePath(
const SecondaryRefProfilePath& secondary_ref_profile_path) {
OR_RETURN(ValidateDexPath(secondary_ref_profile_path.dexPath));
std::filesystem::path dex_path(secondary_ref_profile_path.dexPath);
- return ART_FORMAT(
- "{}/oat/{}.prof", dex_path.parent_path().string(), dex_path.filename().string());
+ return ART_FORMAT("{}/oat/{}.prof{}",
+ dex_path.parent_path().string(),
+ dex_path.filename().string(),
+ secondary_ref_profile_path.isPreReboot ? kPreRebootSuffix : "");
}
Result<std::string> BuildSecondaryCurProfilePath(
@@ -271,7 +290,43 @@ Result<std::string> BuildProfileOrDmPath(const ProfilePath& profile_path) {
Result<std::string> BuildVdexPath(const VdexPath& vdex_path) {
DCHECK(vdex_path.getTag() == VdexPath::artifactsPath);
- return OatPathToVdexPath(OR_RETURN(BuildOatPath(vdex_path.get<VdexPath::artifactsPath>())));
+ return OR_RETURN(BuildArtifactsPath(vdex_path.get<VdexPath::artifactsPath>())).vdex_path;
+}
+
+bool PreRebootFlag(const ProfilePath& profile_path) {
+ switch (profile_path.getTag()) {
+ case ProfilePath::primaryRefProfilePath:
+ return profile_path.get<ProfilePath::primaryRefProfilePath>().isPreReboot;
+ case ProfilePath::secondaryRefProfilePath:
+ return profile_path.get<ProfilePath::secondaryRefProfilePath>().isPreReboot;
+ case ProfilePath::tmpProfilePath:
+ return PreRebootFlag(profile_path.get<ProfilePath::tmpProfilePath>());
+ case ProfilePath::prebuiltProfilePath:
+ case ProfilePath::primaryCurProfilePath:
+ case ProfilePath::secondaryCurProfilePath:
+ case ProfilePath::dexMetadataPath:
+ return false;
+ // No default. All cases should be explicitly handled, or the compilation will fail.
+ }
+ // This should never happen. Just in case we get a non-enumerator value.
+ LOG(FATAL) << ART_FORMAT("Unexpected profile path type {}",
+ fmt::underlying(profile_path.getTag()));
+}
+
+bool PreRebootFlag(const TmpProfilePath& tmp_profile_path) {
+ return PreRebootFlag(tmp_profile_path.finalPath);
+}
+
+bool PreRebootFlag(const OutputProfile& profile) { return PreRebootFlag(profile.profilePath); }
+
+bool PreRebootFlag(const ArtifactsPath& artifacts_path) { return artifacts_path.isPreReboot; }
+
+bool PreRebootFlag(const OutputArtifacts& artifacts) {
+ return PreRebootFlag(artifacts.artifactsPath);
+}
+
+bool PreRebootFlag(const VdexPath& vdex_path) {
+ return PreRebootFlag(vdex_path.get<VdexPath::artifactsPath>());
}
void TestOnlySetListRootDir(std::string_view root_dir) { gListRootDir = root_dir; }
diff --git a/artd/path_utils.h b/artd/path_utils.h
index 9cbec2351a..a4a6e4f2a7 100644
--- a/artd/path_utils.h
+++ b/artd/path_utils.h
@@ -18,16 +18,23 @@
#define ART_ARTD_PATH_UTILS_H_
#include <string>
+#include <type_traits>
#include <vector>
#include "aidl/com/android/server/art/BnArtd.h"
+#include "android-base/logging.h"
#include "android-base/result.h"
-#include "base/file_utils.h"
-#include "fstab/fstab.h"
+#include "base/macros.h"
namespace art {
namespace artd {
+struct RawArtifactsPath {
+ std::string oat_path;
+ std::string vdex_path;
+ std::string art_path;
+};
+
android::base::Result<std::string> GetAndroidDataOrError();
android::base::Result<std::string> GetAndroidExpandOrError();
@@ -48,20 +55,10 @@ android::base::Result<void> ValidateRuntimeArtifactsPath(
android::base::Result<std::string> BuildArtBinPath(const std::string& binary_name);
-// Returns the absolute path to the OAT file built from the `ArtifactsPath`.
-android::base::Result<std::string> BuildOatPath(
+// Returns the absolute paths to files built from the `ArtifactsPath`.
+android::base::Result<RawArtifactsPath> BuildArtifactsPath(
const aidl::com::android::server::art::ArtifactsPath& artifacts_path);
-// Returns the path to the VDEX file that corresponds to the OAT file.
-inline std::string OatPathToVdexPath(const std::string& oat_path) {
- return ReplaceFileExtension(oat_path, "vdex");
-}
-
-// Returns the path to the ART file that corresponds to the OAT file.
-inline std::string OatPathToArtPath(const std::string& oat_path) {
- return ReplaceFileExtension(oat_path, "art");
-}
-
android::base::Result<std::string> BuildPrimaryRefProfilePath(
const aidl::com::android::server::art::ProfilePath::PrimaryRefProfilePath&
primary_ref_profile_path);
@@ -96,6 +93,38 @@ android::base::Result<std::string> BuildProfileOrDmPath(
android::base::Result<std::string> BuildVdexPath(
const aidl::com::android::server::art::VdexPath& vdex_path);
+// Takes an argument of type `WritableProfilePath`. Returns the pre-reboot flag by value if the
+// argument is const, or by reference otherwise.
+template <typename T,
+ typename = std::enable_if_t<
+ std::is_same_v<std::remove_cv_t<T>,
+ aidl::com::android::server::art::ProfilePath::WritableProfilePath>>>
+std::conditional_t<std::is_const_v<T>, bool, bool&> PreRebootFlag(T& profile_path) {
+ switch (profile_path.getTag()) {
+ case T::forPrimary:
+ return profile_path.template get<T::forPrimary>().isPreReboot;
+ case T::forSecondary:
+ return profile_path.template get<T::forSecondary>().isPreReboot;
+ // No default. All cases should be explicitly handled, or the compilation will fail.
+ }
+ // This should never happen. Just in case we get a non-enumerator value.
+ LOG(FATAL) << ART_FORMAT("Unexpected writable profile path type {}",
+ fmt::underlying(profile_path.getTag()));
+}
+
+template bool PreRebootFlag(
+ const aidl::com::android::server::art::ProfilePath::WritableProfilePath& profile_path);
+template bool& PreRebootFlag(
+ aidl::com::android::server::art::ProfilePath::WritableProfilePath& profile_path);
+
+bool PreRebootFlag(const aidl::com::android::server::art::ProfilePath& profile_path);
+bool PreRebootFlag(
+ const aidl::com::android::server::art::ProfilePath::TmpProfilePath& tmp_profile_path);
+bool PreRebootFlag(const aidl::com::android::server::art::OutputProfile& profile);
+bool PreRebootFlag(const aidl::com::android::server::art::ArtifactsPath& artifacts_path);
+bool PreRebootFlag(const aidl::com::android::server::art::OutputArtifacts& artifacts);
+bool PreRebootFlag(const aidl::com::android::server::art::VdexPath& vdex_path);
+
// Sets the root dir for `ListManagedFiles` and `ListRuntimeImageFiles`.
// The passed string must be alive until the test ends.
// For testing use only.
diff --git a/artd/path_utils_test.cc b/artd/path_utils_test.cc
index 5851245eac..116177a7a7 100644
--- a/artd/path_utils_test.cc
+++ b/artd/path_utils_test.cc
@@ -19,6 +19,7 @@
#include "aidl/com/android/server/art/BnArtd.h"
#include "android-base/result-gmock.h"
#include "base/common_art_test.h"
+#include "gmock/gmock.h"
#include "gtest/gtest.h"
namespace art {
@@ -31,6 +32,8 @@ using ::aidl::com::android::server::art::ProfilePath;
using ::android::base::testing::HasError;
using ::android::base::testing::HasValue;
using ::android::base::testing::WithMessage;
+using ::testing::AllOf;
+using ::testing::Field;
using PrebuiltProfilePath = ProfilePath::PrebuiltProfilePath;
using PrimaryCurProfilePath = ProfilePath::PrimaryCurProfilePath;
@@ -50,75 +53,107 @@ TEST_F(PathUtilsTest, BuildArtBinPath) {
EXPECT_THAT(BuildArtBinPath("foo"), HasValue(scratch_dir->GetPath() + "/bin/foo"));
}
-TEST_F(PathUtilsTest, BuildOatPath) {
+TEST_F(PathUtilsTest, BuildArtifactsPath) {
EXPECT_THAT(
- BuildOatPath(ArtifactsPath{.dexPath = "/a/b.apk", .isa = "arm64", .isInDalvikCache = false}),
- HasValue("/a/oat/arm64/b.odex"));
+ BuildArtifactsPath(ArtifactsPath{
+ .dexPath = "/a/b.apk", .isa = "arm64", .isInDalvikCache = false, .isPreReboot = false}),
+ HasValue(AllOf(Field(&RawArtifactsPath::oat_path, "/a/oat/arm64/b.odex"),
+ Field(&RawArtifactsPath::vdex_path, "/a/oat/arm64/b.vdex"),
+ Field(&RawArtifactsPath::art_path, "/a/oat/arm64/b.art"))));
}
-TEST_F(PathUtilsTest, BuildOatPathDalvikCache) {
+TEST_F(PathUtilsTest, BuildArtifactsPathPreReboot) {
EXPECT_THAT(
- BuildOatPath(ArtifactsPath{.dexPath = "/a/b.apk", .isa = "arm64", .isInDalvikCache = true}),
- HasValue(android_data_ + "/dalvik-cache/arm64/a@b.apk@classes.dex"));
+ BuildArtifactsPath(ArtifactsPath{
+ .dexPath = "/a/b.apk", .isa = "arm64", .isInDalvikCache = false, .isPreReboot = true}),
+ HasValue(AllOf(Field(&RawArtifactsPath::oat_path, "/a/oat/arm64/b.odex.staged"),
+ Field(&RawArtifactsPath::vdex_path, "/a/oat/arm64/b.vdex.staged"),
+ Field(&RawArtifactsPath::art_path, "/a/oat/arm64/b.art.staged"))));
}
-TEST_F(PathUtilsTest, BuildOatPathInvalidDexPath) {
+TEST_F(PathUtilsTest, BuildArtifactsPathDalvikCache) {
EXPECT_THAT(
- BuildOatPath(ArtifactsPath{.dexPath = "a/b.apk", .isa = "arm64", .isInDalvikCache = false}),
- HasError(WithMessage("Path 'a/b.apk' is not an absolute path")));
+ BuildArtifactsPath(ArtifactsPath{
+ .dexPath = "/a/b.apk", .isa = "arm64", .isInDalvikCache = true, .isPreReboot = false}),
+ HasValue(AllOf(Field(&RawArtifactsPath::oat_path,
+ android_data_ + "/dalvik-cache/arm64/a@b.apk@classes.dex"),
+ Field(&RawArtifactsPath::vdex_path,
+ android_data_ + "/dalvik-cache/arm64/a@b.apk@classes.vdex"),
+ Field(&RawArtifactsPath::art_path,
+ android_data_ + "/dalvik-cache/arm64/a@b.apk@classes.art"))));
}
-TEST_F(PathUtilsTest, BuildOatPathInvalidIsa) {
- EXPECT_THAT(BuildOatPath(
- ArtifactsPath{.dexPath = "/a/b.apk", .isa = "invalid", .isInDalvikCache = false}),
- HasError(WithMessage("Instruction set 'invalid' is invalid")));
+TEST_F(PathUtilsTest, BuildArtifactsPathDalvikCachePreReboot) {
+ EXPECT_THAT(
+ BuildArtifactsPath(ArtifactsPath{
+ .dexPath = "/a/b.apk", .isa = "arm64", .isInDalvikCache = true, .isPreReboot = true}),
+ HasValue(AllOf(Field(&RawArtifactsPath::oat_path,
+ android_data_ + "/dalvik-cache/arm64/a@b.apk@classes.dex.staged"),
+ Field(&RawArtifactsPath::vdex_path,
+ android_data_ + "/dalvik-cache/arm64/a@b.apk@classes.vdex.staged"),
+ Field(&RawArtifactsPath::art_path,
+ android_data_ + "/dalvik-cache/arm64/a@b.apk@classes.art.staged"))));
}
-TEST_F(PathUtilsTest, OatPathToVdexPath) {
- EXPECT_EQ(OatPathToVdexPath("/a/oat/arm64/b.odex"), "/a/oat/arm64/b.vdex");
+TEST_F(PathUtilsTest, BuildOatPathInvalidDexPath) {
+ EXPECT_THAT(
+ BuildArtifactsPath(ArtifactsPath{
+ .dexPath = "a/b.apk", .isa = "arm64", .isInDalvikCache = false, .isPreReboot = false}),
+ HasError(WithMessage("Path 'a/b.apk' is not an absolute path")));
}
-TEST_F(PathUtilsTest, OatPathToArtPath) {
- EXPECT_EQ(OatPathToArtPath("/a/oat/arm64/b.odex"), "/a/oat/arm64/b.art");
+TEST_F(PathUtilsTest, BuildOatPathInvalidIsa) {
+ EXPECT_THAT(
+ BuildArtifactsPath(ArtifactsPath{
+ .dexPath = "/a/b.apk", .isa = "invalid", .isInDalvikCache = false, .isPreReboot = false}),
+ HasError(WithMessage("Instruction set 'invalid' is invalid")));
}
TEST_F(PathUtilsTest, BuildPrimaryRefProfilePath) {
- EXPECT_THAT(BuildPrimaryRefProfilePath(PrimaryRefProfilePath{.packageName = "com.android.foo",
- .profileName = "primary"}),
- HasValue(android_data_ + "/misc/profiles/ref/com.android.foo/primary.prof"));
+ EXPECT_THAT(
+ BuildPrimaryRefProfilePath(PrimaryRefProfilePath{
+ .packageName = "com.android.foo", .profileName = "primary", .isPreReboot = false}),
+ HasValue(android_data_ + "/misc/profiles/ref/com.android.foo/primary.prof"));
+}
+
+TEST_F(PathUtilsTest, BuildPrimaryRefProfilePathPreReboot) {
+ EXPECT_THAT(BuildPrimaryRefProfilePath(PrimaryRefProfilePath{
+ .packageName = "com.android.foo", .profileName = "primary", .isPreReboot = true}),
+ HasValue(android_data_ + "/misc/profiles/ref/com.android.foo/primary.prof.staged"));
}
TEST_F(PathUtilsTest, BuildPrimaryRefProfilePathPackageNameOk) {
- EXPECT_THAT(BuildPrimaryRefProfilePath(
- PrimaryRefProfilePath{.packageName = "...", .profileName = "primary"}),
+ EXPECT_THAT(BuildPrimaryRefProfilePath(PrimaryRefProfilePath{
+ .packageName = "...", .profileName = "primary", .isPreReboot = false}),
HasValue(android_data_ + "/misc/profiles/ref/.../primary.prof"));
}
TEST_F(PathUtilsTest, BuildPrimaryRefProfilePathPackageNameWrong) {
- EXPECT_THAT(BuildPrimaryRefProfilePath(
- PrimaryRefProfilePath{.packageName = "..", .profileName = "primary"}),
+ EXPECT_THAT(BuildPrimaryRefProfilePath(PrimaryRefProfilePath{
+ .packageName = "..", .profileName = "primary", .isPreReboot = false}),
HasError(WithMessage("Invalid packageName '..'")));
- EXPECT_THAT(BuildPrimaryRefProfilePath(
- PrimaryRefProfilePath{.packageName = "a/b", .profileName = "primary"}),
+ EXPECT_THAT(BuildPrimaryRefProfilePath(PrimaryRefProfilePath{
+ .packageName = "a/b", .profileName = "primary", .isPreReboot = false}),
HasError(WithMessage("packageName 'a/b' has invalid character '/'")));
}
TEST_F(PathUtilsTest, BuildPrimaryRefProfilePathProfileNameOk) {
- EXPECT_THAT(BuildPrimaryRefProfilePath(
- PrimaryRefProfilePath{.packageName = "com.android.foo", .profileName = ".."}),
+ EXPECT_THAT(BuildPrimaryRefProfilePath(PrimaryRefProfilePath{
+ .packageName = "com.android.foo", .profileName = "..", .isPreReboot = false}),
HasValue(android_data_ + "/misc/profiles/ref/com.android.foo/...prof"));
}
TEST_F(PathUtilsTest, BuildPrimaryRefProfilePathProfileNameWrong) {
- EXPECT_THAT(BuildPrimaryRefProfilePath(
- PrimaryRefProfilePath{.packageName = "com.android.foo", .profileName = "a/b"}),
+ EXPECT_THAT(BuildPrimaryRefProfilePath(PrimaryRefProfilePath{
+ .packageName = "com.android.foo", .profileName = "a/b", .isPreReboot = false}),
HasError(WithMessage("profileName 'a/b' has invalid character '/'")));
}
TEST_F(PathUtilsTest, BuildFinalProfilePathForPrimary) {
EXPECT_THAT(BuildFinalProfilePath(TmpProfilePath{
.finalPath = PrimaryRefProfilePath{.packageName = "com.android.foo",
- .profileName = "primary"},
+ .profileName = "primary",
+ .isPreReboot = false},
.id = "12345"}),
HasValue(android_data_ + "/misc/profiles/ref/com.android.foo/primary.prof"));
}
@@ -126,7 +161,8 @@ TEST_F(PathUtilsTest, BuildFinalProfilePathForPrimary) {
TEST_F(PathUtilsTest, BuildFinalProfilePathForSecondary) {
EXPECT_THAT(BuildFinalProfilePath(TmpProfilePath{
.finalPath = SecondaryRefProfilePath{.dexPath = android_data_ +
- "/user/0/com.android.foo/a.apk"},
+ "/user/0/com.android.foo/a.apk",
+ .isPreReboot = false},
.id = "12345"}),
HasValue(android_data_ + "/user/0/com.android.foo/oat/a.apk.prof"));
}
@@ -135,7 +171,8 @@ TEST_F(PathUtilsTest, BuildTmpProfilePathForPrimary) {
EXPECT_THAT(
BuildTmpProfilePath(TmpProfilePath{
.finalPath =
- PrimaryRefProfilePath{.packageName = "com.android.foo", .profileName = "primary"},
+ PrimaryRefProfilePath{
+ .packageName = "com.android.foo", .profileName = "primary", .isPreReboot = false},
.id = "12345"}),
HasValue(android_data_ + "/misc/profiles/ref/com.android.foo/primary.prof.12345.tmp"));
}
@@ -143,7 +180,8 @@ TEST_F(PathUtilsTest, BuildTmpProfilePathForPrimary) {
TEST_F(PathUtilsTest, BuildTmpProfilePathForSecondary) {
EXPECT_THAT(BuildTmpProfilePath(TmpProfilePath{
.finalPath = SecondaryRefProfilePath{.dexPath = android_data_ +
- "/user/0/com.android.foo/a.apk"},
+ "/user/0/com.android.foo/a.apk",
+ .isPreReboot = false},
.id = "12345"}),
HasValue(android_data_ + "/user/0/com.android.foo/oat/a.apk.prof.12345.tmp"));
}
@@ -151,7 +189,8 @@ TEST_F(PathUtilsTest, BuildTmpProfilePathForSecondary) {
TEST_F(PathUtilsTest, BuildTmpProfilePathIdWrong) {
EXPECT_THAT(BuildTmpProfilePath(TmpProfilePath{
.finalPath = PrimaryRefProfilePath{.packageName = "com.android.foo",
- .profileName = "primary"},
+ .profileName = "primary",
+ .isPreReboot = false},
.id = "123/45"}),
HasError(WithMessage("id '123/45' has invalid character '/'")));
}
@@ -168,9 +207,16 @@ TEST_F(PathUtilsTest, BuildPrimaryCurProfilePath) {
}
TEST_F(PathUtilsTest, BuildSecondaryRefProfilePath) {
+ EXPECT_THAT(
+ BuildSecondaryRefProfilePath(SecondaryRefProfilePath{
+ .dexPath = android_data_ + "/user/0/com.android.foo/a.apk", .isPreReboot = false}),
+ HasValue(android_data_ + "/user/0/com.android.foo/oat/a.apk.prof"));
+}
+
+TEST_F(PathUtilsTest, BuildSecondaryRefProfilePathPreReboot) {
EXPECT_THAT(BuildSecondaryRefProfilePath(SecondaryRefProfilePath{
- .dexPath = android_data_ + "/user/0/com.android.foo/a.apk"}),
- HasValue(android_data_ + "/user/0/com.android.foo/oat/a.apk.prof"));
+ .dexPath = android_data_ + "/user/0/com.android.foo/a.apk", .isPreReboot = true}),
+ HasValue(android_data_ + "/user/0/com.android.foo/oat/a.apk.prof.staged"));
}
TEST_F(PathUtilsTest, BuildSecondaryCurProfilePath) {
@@ -184,13 +230,15 @@ TEST_F(PathUtilsTest, BuildDexMetadataPath) {
}
TEST_F(PathUtilsTest, BuildProfilePath) {
- EXPECT_THAT(BuildProfileOrDmPath(PrimaryRefProfilePath{.packageName = "com.android.foo",
- .profileName = "primary"}),
- HasValue(android_data_ + "/misc/profiles/ref/com.android.foo/primary.prof"));
+ EXPECT_THAT(
+ BuildProfileOrDmPath(PrimaryRefProfilePath{
+ .packageName = "com.android.foo", .profileName = "primary", .isPreReboot = false}),
+ HasValue(android_data_ + "/misc/profiles/ref/com.android.foo/primary.prof"));
EXPECT_THAT(
BuildProfileOrDmPath(TmpProfilePath{
.finalPath =
- PrimaryRefProfilePath{.packageName = "com.android.foo", .profileName = "primary"},
+ PrimaryRefProfilePath{
+ .packageName = "com.android.foo", .profileName = "primary", .isPreReboot = false},
.id = "12345"}),
HasValue(android_data_ + "/misc/profiles/ref/com.android.foo/primary.prof.12345.tmp"));
EXPECT_THAT(BuildProfileOrDmPath(PrebuiltProfilePath{.dexPath = "/a/b.apk"}),
diff --git a/libartservice/service/java/com/android/server/art/AidlUtils.java b/libartservice/service/java/com/android/server/art/AidlUtils.java
index 4a1b75eaab..d42a6539c4 100644
--- a/libartservice/service/java/com/android/server/art/AidlUtils.java
+++ b/libartservice/service/java/com/android/server/art/AidlUtils.java
@@ -34,16 +34,25 @@ public final class AidlUtils {
private AidlUtils() {}
@NonNull
- public static ArtifactsPath buildArtifactsPath(
- @NonNull String dexPath, @NonNull String isa, boolean isInDalvikCache) {
+ private static ArtifactsPath buildArtifactsPath(@NonNull String dexPath, @NonNull String isa,
+ boolean isInDalvikCache, boolean isPreReboot) {
var artifactsPath = new ArtifactsPath();
artifactsPath.dexPath = dexPath;
artifactsPath.isa = isa;
artifactsPath.isInDalvikCache = isInDalvikCache;
+ artifactsPath.isPreReboot = isPreReboot;
return artifactsPath;
}
@NonNull
+ public static ArtifactsPath buildArtifactsPathAsInput(
+ @NonNull String dexPath, @NonNull String isa, boolean isInDalvikCache) {
+ // The callers expect artifacts to be used as inputs, so we should always pick the
+ // non-Pre-reboot ones.
+ return buildArtifactsPath(dexPath, isa, isInDalvikCache, false /* isPreReboot */);
+ }
+
+ @NonNull
public static FsPermission buildFsPermission(
int uid, int gid, boolean isOtherReadable, boolean isOtherExecutable) {
var fsPermission = new FsPermission();
@@ -78,34 +87,41 @@ public final class AidlUtils {
@NonNull
public static OutputArtifacts buildOutputArtifacts(@NonNull String dexPath, @NonNull String isa,
- boolean isInDalvikCache, @NonNull PermissionSettings permissionSettings) {
+ boolean isInDalvikCache, @NonNull PermissionSettings permissionSettings,
+ boolean isPreReboot) {
var outputArtifacts = new OutputArtifacts();
- outputArtifacts.artifactsPath = buildArtifactsPath(dexPath, isa, isInDalvikCache);
+ outputArtifacts.artifactsPath =
+ buildArtifactsPath(dexPath, isa, isInDalvikCache, isPreReboot);
outputArtifacts.permissionSettings = permissionSettings;
return outputArtifacts;
}
@NonNull
- public static PrimaryRefProfilePath buildPrimaryRefProfilePath(
- @NonNull String packageName, @NonNull String profileName) {
+ private static PrimaryRefProfilePath buildPrimaryRefProfilePath(
+ @NonNull String packageName, @NonNull String profileName, boolean isPreReboot) {
var primaryRefProfilePath = new PrimaryRefProfilePath();
primaryRefProfilePath.packageName = packageName;
primaryRefProfilePath.profileName = profileName;
+ primaryRefProfilePath.isPreReboot = isPreReboot;
return primaryRefProfilePath;
}
@NonNull
- public static SecondaryRefProfilePath buildSecondaryRefProfilePath(@NonNull String dexPath) {
+ private static SecondaryRefProfilePath buildSecondaryRefProfilePath(
+ @NonNull String dexPath, boolean isPreReboot) {
var secondaryRefProfilePath = new SecondaryRefProfilePath();
secondaryRefProfilePath.dexPath = dexPath;
+ secondaryRefProfilePath.isPreReboot = isPreReboot;
return secondaryRefProfilePath;
}
@NonNull
- public static ProfilePath buildProfilePathForPrimaryRef(
+ public static ProfilePath buildProfilePathForPrimaryRefAsInput(
@NonNull String packageName, @NonNull String profileName) {
+ // The callers expect a profile to be used as an input, so we should always pick the
+ // non-Pre-reboot one.
return ProfilePath.primaryRefProfilePath(
- buildPrimaryRefProfilePath(packageName, profileName));
+ buildPrimaryRefProfilePath(packageName, profileName, false /* isPreReboot */));
}
@NonNull
@@ -131,8 +147,11 @@ public final class AidlUtils {
}
@NonNull
- public static ProfilePath buildProfilePathForSecondaryRef(@NonNull String dexPath) {
- return ProfilePath.secondaryRefProfilePath(buildSecondaryRefProfilePath(dexPath));
+ public static ProfilePath buildProfilePathForSecondaryRefAsInput(@NonNull String dexPath) {
+ // The callers expect a profile to be used as an input, so we should always pick the
+ // non-Pre-reboot one.
+ return ProfilePath.secondaryRefProfilePath(
+ buildSecondaryRefProfilePath(dexPath, false /* isPreReboot */));
}
@NonNull
@@ -156,18 +175,18 @@ public final class AidlUtils {
@NonNull
public static OutputProfile buildOutputProfileForPrimary(@NonNull String packageName,
- @NonNull String profileName, int uid, int gid, boolean isPublic) {
- return buildOutputProfile(WritableProfilePath.forPrimary(
- buildPrimaryRefProfilePath(packageName, profileName)),
+ @NonNull String profileName, int uid, int gid, boolean isPublic, boolean isPreReboot) {
+ return buildOutputProfile(WritableProfilePath.forPrimary(buildPrimaryRefProfilePath(
+ packageName, profileName, isPreReboot)),
uid, gid, isPublic);
}
@NonNull
public static OutputProfile buildOutputProfileForSecondary(
- @NonNull String dexPath, int uid, int gid, boolean isPublic) {
- return buildOutputProfile(
- WritableProfilePath.forSecondary(buildSecondaryRefProfilePath(dexPath)), uid, gid,
- isPublic);
+ @NonNull String dexPath, int uid, int gid, boolean isPublic, boolean isPreReboot) {
+ return buildOutputProfile(WritableProfilePath.forSecondary(
+ buildSecondaryRefProfilePath(dexPath, isPreReboot)),
+ uid, gid, isPublic);
}
@NonNull
@@ -190,13 +209,15 @@ public final class AidlUtils {
@NonNull
public static String toString(@NonNull PrimaryRefProfilePath profile) {
- return String.format("PrimaryRefProfilePath[packageName = %s, profileName = %s]",
- profile.packageName, profile.profileName);
+ return String.format(
+ "PrimaryRefProfilePath[packageName = %s, profileName = %s, isPreReboot = %b]",
+ profile.packageName, profile.profileName, profile.isPreReboot);
}
@NonNull
public static String toString(@NonNull SecondaryRefProfilePath profile) {
- return String.format("SecondaryRefProfilePath[dexPath = %s]", profile.dexPath);
+ return String.format("SecondaryRefProfilePath[dexPath = %s, isPreReboot = %b]",
+ profile.dexPath, profile.isPreReboot);
}
@NonNull
diff --git a/libartservice/service/java/com/android/server/art/ArtFileManager.java b/libartservice/service/java/com/android/server/art/ArtFileManager.java
index b46c8df9f2..234ca01f7c 100644
--- a/libartservice/service/java/com/android/server/art/ArtFileManager.java
+++ b/libartservice/service/java/com/android/server/art/ArtFileManager.java
@@ -111,7 +111,7 @@ public class ArtFileManager {
boolean isInDalvikCache = Utils.isInDalvikCache(pkgState, mInjector.getArtd());
for (PrimaryDexInfo dexInfo : PrimaryDexUtils.getDexInfo(pkg)) {
for (Abi abi : Utils.getAllAbis(pkgState)) {
- artifacts.add(AidlUtils.buildArtifactsPath(
+ artifacts.add(AidlUtils.buildArtifactsPathAsInput(
dexInfo.dexPath(), abi.isa(), isInDalvikCache));
// Runtime images are only generated for primary dex files.
runtimeArtifacts.add(AidlUtils.buildRuntimeArtifactsPath(
@@ -123,7 +123,7 @@ public class ArtFileManager {
if (options.forSecondaryDex()) {
for (SecondaryDexInfo dexInfo : getSecondaryDexInfo(pkgState, options)) {
for (Abi abi : Utils.getAllAbisForNames(dexInfo.abiNames(), pkgState)) {
- artifacts.add(AidlUtils.buildArtifactsPath(
+ artifacts.add(AidlUtils.buildArtifactsPathAsInput(
dexInfo.dexPath(), abi.isa(), false /* isInDalvikCache */));
}
}
@@ -153,8 +153,9 @@ public class ArtFileManager {
dexInfo.dexPath(), abi.isa(), dexInfo.classLoaderContext());
if (result.artifactsLocation == ArtifactsLocation.DALVIK_CACHE
|| result.artifactsLocation == ArtifactsLocation.NEXT_TO_DEX) {
- ArtifactsPath thisArtifacts = AidlUtils.buildArtifactsPath(dexInfo.dexPath(),
- abi.isa(), result.artifactsLocation == ArtifactsLocation.DALVIK_CACHE);
+ ArtifactsPath thisArtifacts =
+ AidlUtils.buildArtifactsPathAsInput(dexInfo.dexPath(), abi.isa(),
+ result.artifactsLocation == ArtifactsLocation.DALVIK_CACHE);
if (result.compilationReason.equals(ArtConstants.REASON_VDEX)) {
// Only the VDEX file is usable.
vdexFiles.add(VdexPath.artifactsPath(thisArtifacts));
@@ -190,7 +191,7 @@ public class ArtFileManager {
if (options.forPrimaryDex()) {
for (PrimaryDexInfo dexInfo : PrimaryDexUtils.getDexInfo(pkg)) {
- refProfiles.add(PrimaryDexUtils.buildRefProfilePath(pkgState, dexInfo));
+ refProfiles.add(PrimaryDexUtils.buildRefProfilePathAsInput(pkgState, dexInfo));
curProfiles.addAll(mInjector.isSystemOrRootOrShell()
? PrimaryDexUtils.getCurProfiles(
mInjector.getUserManager(), pkgState, dexInfo)
@@ -206,7 +207,8 @@ public class ArtFileManager {
&& !mInjector.getCallingUserHandle().equals(dexInfo.userHandle())) {
continue;
}
- refProfiles.add(AidlUtils.buildProfilePathForSecondaryRef(dexInfo.dexPath()));
+ refProfiles.add(
+ AidlUtils.buildProfilePathForSecondaryRefAsInput(dexInfo.dexPath()));
curProfiles.add(AidlUtils.buildProfilePathForSecondaryCur(dexInfo.dexPath()));
}
}
diff --git a/libartservice/service/java/com/android/server/art/ArtManagerLocal.java b/libartservice/service/java/com/android/server/art/ArtManagerLocal.java
index b548f9d83d..a9a357776e 100644
--- a/libartservice/service/java/com/android/server/art/ArtManagerLocal.java
+++ b/libartservice/service/java/com/android/server/art/ArtManagerLocal.java
@@ -743,12 +743,14 @@ public final class ArtManagerLocal {
List<ProfilePath> profiles = new ArrayList<>();
+ // Doesn't support Pre-reboot.
InitProfileResult result = Utils.getOrInitReferenceProfile(mInjector.getArtd(),
- dexInfo.dexPath(), PrimaryDexUtils.buildRefProfilePath(pkgState, dexInfo),
+ dexInfo.dexPath(),
+ PrimaryDexUtils.buildRefProfilePathAsInput(pkgState, dexInfo),
PrimaryDexUtils.getExternalProfiles(dexInfo),
dmInfo.config().getEnableEmbeddedProfile(),
PrimaryDexUtils.buildOutputProfile(pkgState, dexInfo, Process.SYSTEM_UID,
- Process.SYSTEM_UID, false /* isPublic */));
+ Process.SYSTEM_UID, false /* isPublic */, false /* isPreReboot */));
if (!result.externalProfileErrors().isEmpty()) {
Log.e(TAG,
"Error occurred when initializing from external profiles: "
@@ -764,8 +766,10 @@ public final class ArtManagerLocal {
profiles.addAll(
PrimaryDexUtils.getCurProfiles(mInjector.getUserManager(), pkgState, dexInfo));
- OutputProfile output = PrimaryDexUtils.buildOutputProfile(pkgState, dexInfo,
- Process.SYSTEM_UID, Process.SYSTEM_UID, false /* isPublic */);
+ // Doesn't support Pre-reboot.
+ OutputProfile output =
+ PrimaryDexUtils.buildOutputProfile(pkgState, dexInfo, Process.SYSTEM_UID,
+ Process.SYSTEM_UID, false /* isPublic */, false /* isPreReboot */);
try {
return mergeProfilesAndGetFd(profiles, output, List.of(dexInfo.dexPath()), options);
@@ -805,7 +809,7 @@ public final class ArtManagerLocal {
List<ProfilePath> profiles = new ArrayList<>();
// System server profiles.
- profiles.add(AidlUtils.buildProfilePathForPrimaryRef(
+ profiles.add(AidlUtils.buildProfilePathForPrimaryRefAsInput(
Utils.PLATFORM_PACKAGE_NAME, PrimaryDexUtils.PROFILE_PRIMARY));
for (UserHandle handle :
mInjector.getUserManager().getUserHandles(true /* excludeDying */)) {
@@ -825,9 +829,10 @@ public final class ArtManagerLocal {
}
});
+ // Doesn't support Pre-reboot.
OutputProfile output = AidlUtils.buildOutputProfileForPrimary(Utils.PLATFORM_PACKAGE_NAME,
PrimaryDexUtils.PROFILE_PRIMARY, Process.SYSTEM_UID, Process.SYSTEM_UID,
- false /* isPublic */);
+ false /* isPublic */, false /* isPreReboot */);
List<String> dexPaths = Arrays.stream(CLASSPATHS_FOR_BOOT_IMAGE_PROFILE)
.map(envVar -> Constants.getenv(envVar))
diff --git a/libartservice/service/java/com/android/server/art/DexUseManagerLocal.java b/libartservice/service/java/com/android/server/art/DexUseManagerLocal.java
index 04414d0369..7c231c9ce0 100644
--- a/libartservice/service/java/com/android/server/art/DexUseManagerLocal.java
+++ b/libartservice/service/java/com/android/server/art/DexUseManagerLocal.java
@@ -168,6 +168,7 @@ public class DexUseManagerLocal {
/** Notifies dex use manager that {@link Context#registerReceiver} is ready for use. */
public void systemReady() {
+ Utils.check(!mInjector.isPreReboot());
// Save the data when the device is being shut down. The receiver is blocking, with a
// 10s timeout.
mInjector.getContext().registerReceiver(new BroadcastReceiver() {
@@ -528,6 +529,7 @@ public class DexUseManagerLocal {
}
private void save() {
+ Utils.check(!mInjector.isPreReboot());
var builder = DexUseProto.newBuilder();
int thisRevision;
synchronized (mLock) {
@@ -561,6 +563,7 @@ public class DexUseManagerLocal {
}
private void maybeSaveAsync() {
+ Utils.check(!mInjector.isPreReboot());
mDebouncer.maybeRunAsync(this::save);
}
@@ -1163,7 +1166,7 @@ public class DexUseManagerLocal {
mContext = context;
// Call the getters for various dependencies, to ensure correct initialization order.
- ArtModuleServiceInitializer.getArtModuleServiceManager();
+ GlobalInjector.getInstance().checkArtModuleServiceManager();
getPackageManagerLocal();
}
@@ -1199,6 +1202,10 @@ public class DexUseManagerLocal {
}
}
+ public boolean isPreReboot() {
+ return GlobalInjector.getInstance().isPreReboot();
+ }
+
@NonNull
private PackageManagerLocal getPackageManagerLocal() {
return Objects.requireNonNull(
diff --git a/libartservice/service/java/com/android/server/art/Dexopter.java b/libartservice/service/java/com/android/server/art/Dexopter.java
index d8d6b3d5c6..69b861527e 100644
--- a/libartservice/service/java/com/android/server/art/Dexopter.java
+++ b/libartservice/service/java/com/android/server/art/Dexopter.java
@@ -293,7 +293,9 @@ public abstract class Dexopter<DexInfoType extends DetailedDexInfo> {
profile = null;
}
}
- if (profileMerged) {
+ // We keep the current profiles in the Pre-reboot Dexopt case, to leave it to
+ // background dexopt.
+ if (profileMerged && !mInjector.isPreReboot()) {
// Note that this is just an optimization, to reduce the amount of data that
// the runtime writes on every profile save. The profile merge result on the
// next run won't change regardless of whether the cleanup is done or not
@@ -393,8 +395,8 @@ public abstract class Dexopter<DexInfoType extends DetailedDexInfo> {
private InitProfileResult getOrInitReferenceProfile(
@NonNull DexInfoType dexInfo, boolean enableEmbeddedProfile) throws RemoteException {
return Utils.getOrInitReferenceProfile(mInjector.getArtd(), dexInfo.dexPath(),
- buildRefProfilePath(dexInfo), getExternalProfiles(dexInfo), enableEmbeddedProfile,
- buildOutputProfile(dexInfo, true /* isPublic */));
+ buildRefProfilePathAsInput(dexInfo), getExternalProfiles(dexInfo),
+ enableEmbeddedProfile, buildOutputProfile(dexInfo, true /* isPublic */));
}
@Nullable
@@ -472,7 +474,7 @@ public abstract class Dexopter<DexInfoType extends DetailedDexInfo> {
dexoptTrigger |= DexoptTrigger.COMPILER_FILTER_IS_SAME;
}
- ArtifactsPath existingArtifactsPath = AidlUtils.buildArtifactsPath(
+ ArtifactsPath existingArtifactsPath = AidlUtils.buildArtifactsPathAsInput(
target.dexInfo().dexPath(), target.isa(), target.isInDalvikCache());
if (options.needsToBePublic()
@@ -493,8 +495,9 @@ public abstract class Dexopter<DexInfoType extends DetailedDexInfo> {
@NonNull PermissionSettings permissionSettings, @PriorityClass int priorityClass,
@NonNull DexoptOptions dexoptOptions, IArtdCancellationSignal artdCancellationSignal)
throws RemoteException {
- OutputArtifacts outputArtifacts = AidlUtils.buildOutputArtifacts(target.dexInfo().dexPath(),
- target.isa(), target.isInDalvikCache(), permissionSettings);
+ OutputArtifacts outputArtifacts =
+ AidlUtils.buildOutputArtifacts(target.dexInfo().dexPath(), target.isa(),
+ target.isInDalvikCache(), permissionSettings, mInjector.isPreReboot());
VdexPath inputVdex =
getInputVdex(getDexoptNeededResult, target.dexInfo().dexPath(), target.isa());
@@ -527,7 +530,9 @@ public abstract class Dexopter<DexInfoType extends DetailedDexInfo> {
// images are still usable, technically, they can still be used to improve runtime
// performance; if they are no longer usable, they will be deleted by the file GC during the
// daily background dexopt job anyway.
- if (!result.cancelled) {
+ // We keep the runtime artifacts in the Pre-reboot Dexopt case because they are still needed
+ // before the reboot.
+ if (!result.cancelled && !mInjector.isPreReboot()) {
mInjector.getArtd().deleteRuntimeArtifacts(AidlUtils.buildRuntimeArtifactsPath(
mPkgState.getPackageName(), target.dexInfo().dexPath(), target.isa()));
}
@@ -543,11 +548,11 @@ public abstract class Dexopter<DexInfoType extends DetailedDexInfo> {
}
switch (getDexoptNeededResult.artifactsLocation) {
case ArtifactsLocation.DALVIK_CACHE:
- return VdexPath.artifactsPath(
- AidlUtils.buildArtifactsPath(dexPath, isa, true /* isInDalvikCache */));
+ return VdexPath.artifactsPath(AidlUtils.buildArtifactsPathAsInput(
+ dexPath, isa, true /* isInDalvikCache */));
case ArtifactsLocation.NEXT_TO_DEX:
- return VdexPath.artifactsPath(
- AidlUtils.buildArtifactsPath(dexPath, isa, false /* isInDalvikCache */));
+ return VdexPath.artifactsPath(AidlUtils.buildArtifactsPathAsInput(
+ dexPath, isa, false /* isInDalvikCache */));
case ArtifactsLocation.DM:
// The DM file is passed to dex2oat as a separate flag whenever it exists.
return null;
@@ -635,7 +640,8 @@ public abstract class Dexopter<DexInfoType extends DetailedDexInfo> {
@NonNull protected abstract List<Abi> getAllAbis(@NonNull DexInfoType dexInfo);
/** Returns the path to the reference profile of the given dex file. */
- @NonNull protected abstract ProfilePath buildRefProfilePath(@NonNull DexInfoType dexInfo);
+ @NonNull
+ protected abstract ProfilePath buildRefProfilePathAsInput(@NonNull DexInfoType dexInfo);
/**
* Returns the data structure that represents the temporary profile to use during processing.
@@ -773,5 +779,9 @@ public abstract class Dexopter<DexInfoType extends DetailedDexInfo> {
public DexMetadataHelper getDexMetadataHelper() {
return new DexMetadataHelper();
}
+
+ public boolean isPreReboot() {
+ return GlobalInjector.getInstance().isPreReboot();
+ }
}
}
diff --git a/libartservice/service/java/com/android/server/art/PrimaryDexUtils.java b/libartservice/service/java/com/android/server/art/PrimaryDexUtils.java
index 4615886625..c37fdbe6e3 100644
--- a/libartservice/service/java/com/android/server/art/PrimaryDexUtils.java
+++ b/libartservice/service/java/com/android/server/art/PrimaryDexUtils.java
@@ -312,18 +312,20 @@ public class PrimaryDexUtils {
}
@NonNull
- public static ProfilePath buildRefProfilePath(
+ public static ProfilePath buildRefProfilePathAsInput(
@NonNull PackageState pkgState, @NonNull PrimaryDexInfo dexInfo) {
String profileName = getProfileName(dexInfo.splitName());
- return AidlUtils.buildProfilePathForPrimaryRef(pkgState.getPackageName(), profileName);
+ return AidlUtils.buildProfilePathForPrimaryRefAsInput(
+ pkgState.getPackageName(), profileName);
}
@NonNull
public static OutputProfile buildOutputProfile(@NonNull PackageState pkgState,
- @NonNull PrimaryDexInfo dexInfo, int uid, int gid, boolean isPublic) {
+ @NonNull PrimaryDexInfo dexInfo, int uid, int gid, boolean isPublic,
+ boolean isPreReboot) {
String profileName = getProfileName(dexInfo.splitName());
return AidlUtils.buildOutputProfileForPrimary(
- pkgState.getPackageName(), profileName, uid, gid, isPublic);
+ pkgState.getPackageName(), profileName, uid, gid, isPublic, isPreReboot);
}
@NonNull
diff --git a/libartservice/service/java/com/android/server/art/PrimaryDexopter.java b/libartservice/service/java/com/android/server/art/PrimaryDexopter.java
index 38fca5f5f0..6ac7988f9e 100644
--- a/libartservice/service/java/com/android/server/art/PrimaryDexopter.java
+++ b/libartservice/service/java/com/android/server/art/PrimaryDexopter.java
@@ -148,16 +148,16 @@ public class PrimaryDexopter extends Dexopter<DetailedPrimaryDexInfo> {
@Override
@NonNull
- protected ProfilePath buildRefProfilePath(@NonNull DetailedPrimaryDexInfo dexInfo) {
- return PrimaryDexUtils.buildRefProfilePath(mPkgState, dexInfo);
+ protected ProfilePath buildRefProfilePathAsInput(@NonNull DetailedPrimaryDexInfo dexInfo) {
+ return PrimaryDexUtils.buildRefProfilePathAsInput(mPkgState, dexInfo);
}
@Override
@NonNull
protected OutputProfile buildOutputProfile(
@NonNull DetailedPrimaryDexInfo dexInfo, boolean isPublic) {
- return PrimaryDexUtils.buildOutputProfile(
- mPkgState, dexInfo, Process.SYSTEM_UID, mSharedGid, isPublic);
+ return PrimaryDexUtils.buildOutputProfile(mPkgState, dexInfo, Process.SYSTEM_UID,
+ mSharedGid, isPublic, mInjector.isPreReboot());
}
@Override
diff --git a/libartservice/service/java/com/android/server/art/SecondaryDexopter.java b/libartservice/service/java/com/android/server/art/SecondaryDexopter.java
index 2841ee278b..fe0cdb0091 100644
--- a/libartservice/service/java/com/android/server/art/SecondaryDexopter.java
+++ b/libartservice/service/java/com/android/server/art/SecondaryDexopter.java
@@ -116,8 +116,8 @@ public class SecondaryDexopter extends Dexopter<CheckedSecondaryDexInfo> {
@Override
@NonNull
- protected ProfilePath buildRefProfilePath(@NonNull CheckedSecondaryDexInfo dexInfo) {
- return AidlUtils.buildProfilePathForSecondaryRef(dexInfo.dexPath());
+ protected ProfilePath buildRefProfilePathAsInput(@NonNull CheckedSecondaryDexInfo dexInfo) {
+ return AidlUtils.buildProfilePathForSecondaryRefAsInput(dexInfo.dexPath());
}
@Override
@@ -125,7 +125,8 @@ public class SecondaryDexopter extends Dexopter<CheckedSecondaryDexInfo> {
protected OutputProfile buildOutputProfile(
@NonNull CheckedSecondaryDexInfo dexInfo, boolean isPublic) {
int uid = getUid(dexInfo);
- return AidlUtils.buildOutputProfileForSecondary(dexInfo.dexPath(), uid, uid, isPublic);
+ return AidlUtils.buildOutputProfileForSecondary(
+ dexInfo.dexPath(), uid, uid, isPublic, mInjector.isPreReboot());
}
@Override
diff --git a/libartservice/service/javatests/com/android/server/art/ArtManagerLocalTest.java b/libartservice/service/javatests/com/android/server/art/ArtManagerLocalTest.java
index b7d67eccc3..fa217ab89d 100644
--- a/libartservice/service/javatests/com/android/server/art/ArtManagerLocalTest.java
+++ b/libartservice/service/javatests/com/android/server/art/ArtManagerLocalTest.java
@@ -284,17 +284,17 @@ public class ArtManagerLocalTest {
assertThat(result.getFreedBytes())
.isEqualTo(6 * DEXOPT_ARTIFACTS_FREED + 4 * RUNTIME_ARTIFACTS_FREED);
- verify(mArtd).deleteArtifacts(deepEq(AidlUtils.buildArtifactsPath(
+ verify(mArtd).deleteArtifacts(deepEq(AidlUtils.buildArtifactsPathAsInput(
"/somewhere/app/foo/base.apk", "arm64", mIsInDalvikCache)));
- verify(mArtd).deleteArtifacts(deepEq(AidlUtils.buildArtifactsPath(
+ verify(mArtd).deleteArtifacts(deepEq(AidlUtils.buildArtifactsPathAsInput(
"/somewhere/app/foo/base.apk", "arm", mIsInDalvikCache)));
- verify(mArtd).deleteArtifacts(deepEq(AidlUtils.buildArtifactsPath(
+ verify(mArtd).deleteArtifacts(deepEq(AidlUtils.buildArtifactsPathAsInput(
"/somewhere/app/foo/split_0.apk", "arm64", mIsInDalvikCache)));
- verify(mArtd).deleteArtifacts(deepEq(AidlUtils.buildArtifactsPath(
+ verify(mArtd).deleteArtifacts(deepEq(AidlUtils.buildArtifactsPathAsInput(
"/somewhere/app/foo/split_0.apk", "arm", mIsInDalvikCache)));
- verify(mArtd).deleteArtifacts(deepEq(AidlUtils.buildArtifactsPath(
+ verify(mArtd).deleteArtifacts(deepEq(AidlUtils.buildArtifactsPathAsInput(
"/data/user/0/foo/1.apk", "arm64", false /* isInDalvikCache */)));
- verify(mArtd).deleteArtifacts(deepEq(AidlUtils.buildArtifactsPath(
+ verify(mArtd).deleteArtifacts(deepEq(AidlUtils.buildArtifactsPathAsInput(
"/data/user/0/foo/not_found.apk", "arm64", false /* isInDalvikCache */)));
verify(mArtd).deleteRuntimeArtifacts(deepEq(AidlUtils.buildRuntimeArtifactsPath(
@@ -331,13 +331,13 @@ public class ArtManagerLocalTest {
assertThat(result.getFreedBytes())
.isEqualTo(6 * DEXOPT_ARTIFACTS_FREED + 4 * RUNTIME_ARTIFACTS_FREED);
- verify(mArtd).deleteArtifacts(deepEq(AidlUtils.buildArtifactsPath(
+ verify(mArtd).deleteArtifacts(deepEq(AidlUtils.buildArtifactsPathAsInput(
"/somewhere/app/foo/base.apk", "x86_64", mIsInDalvikCache)));
- verify(mArtd).deleteArtifacts(deepEq(AidlUtils.buildArtifactsPath(
+ verify(mArtd).deleteArtifacts(deepEq(AidlUtils.buildArtifactsPathAsInput(
"/somewhere/app/foo/base.apk", "x86", mIsInDalvikCache)));
- verify(mArtd).deleteArtifacts(deepEq(AidlUtils.buildArtifactsPath(
+ verify(mArtd).deleteArtifacts(deepEq(AidlUtils.buildArtifactsPathAsInput(
"/somewhere/app/foo/split_0.apk", "x86_64", mIsInDalvikCache)));
- verify(mArtd).deleteArtifacts(deepEq(AidlUtils.buildArtifactsPath(
+ verify(mArtd).deleteArtifacts(deepEq(AidlUtils.buildArtifactsPathAsInput(
"/somewhere/app/foo/split_0.apk", "x86", mIsInDalvikCache)));
verify(mArtd).deleteRuntimeArtifacts(deepEq(AidlUtils.buildRuntimeArtifactsPath(
@@ -350,9 +350,9 @@ public class ArtManagerLocalTest {
PKG_NAME_1, "/somewhere/app/foo/split_0.apk", "x86")));
// We assume that the ISA got from `DexUseManagerLocal` is already the translated one.
- verify(mArtd).deleteArtifacts(deepEq(AidlUtils.buildArtifactsPath(
+ verify(mArtd).deleteArtifacts(deepEq(AidlUtils.buildArtifactsPathAsInput(
"/data/user/0/foo/1.apk", "x86_64", false /* isInDalvikCache */)));
- verify(mArtd).deleteArtifacts(deepEq(AidlUtils.buildArtifactsPath(
+ verify(mArtd).deleteArtifacts(deepEq(AidlUtils.buildArtifactsPathAsInput(
"/data/user/0/foo/not_found.apk", "x86_64", false /* isInDalvikCache */)));
// Verify that there are no more calls than the ones above.
@@ -462,19 +462,19 @@ public class ArtManagerLocalTest {
mArtManagerLocal.clearAppProfiles(mSnapshot, PKG_NAME_1);
verify(mArtd).deleteProfile(
- deepEq(AidlUtils.buildProfilePathForPrimaryRef(PKG_NAME_1, "primary")));
+ deepEq(AidlUtils.buildProfilePathForPrimaryRefAsInput(PKG_NAME_1, "primary")));
verify(mArtd).deleteProfile(deepEq(
AidlUtils.buildProfilePathForPrimaryCur(0 /* userId */, PKG_NAME_1, "primary")));
verify(mArtd).deleteProfile(deepEq(
AidlUtils.buildProfilePathForPrimaryCur(1 /* userId */, PKG_NAME_1, "primary")));
verify(mArtd).deleteProfile(
- deepEq(AidlUtils.buildProfilePathForSecondaryRef("/data/user/0/foo/1.apk")));
+ deepEq(AidlUtils.buildProfilePathForSecondaryRefAsInput("/data/user/0/foo/1.apk")));
verify(mArtd).deleteProfile(
deepEq(AidlUtils.buildProfilePathForSecondaryCur("/data/user/0/foo/1.apk")));
- verify(mArtd).deleteProfile(deepEq(
- AidlUtils.buildProfilePathForSecondaryRef("/data/user/0/foo/not_found.apk")));
+ verify(mArtd).deleteProfile(deepEq(AidlUtils.buildProfilePathForSecondaryRefAsInput(
+ "/data/user/0/foo/not_found.apk")));
verify(mArtd).deleteProfile(deepEq(
AidlUtils.buildProfilePathForSecondaryCur("/data/user/0/foo/not_found.apk")));
}
@@ -521,19 +521,19 @@ public class ArtManagerLocalTest {
.isSameInstanceAs(result);
verify(mArtd).deleteProfile(
- deepEq(AidlUtils.buildProfilePathForPrimaryRef(PKG_NAME_1, "primary")));
+ deepEq(AidlUtils.buildProfilePathForPrimaryRefAsInput(PKG_NAME_1, "primary")));
verify(mArtd).deleteProfile(deepEq(
AidlUtils.buildProfilePathForPrimaryCur(0 /* userId */, PKG_NAME_1, "primary")));
verify(mArtd).deleteProfile(deepEq(
AidlUtils.buildProfilePathForPrimaryCur(1 /* userId */, PKG_NAME_1, "primary")));
- verify(mArtd).deleteArtifacts(deepEq(AidlUtils.buildArtifactsPath(
+ verify(mArtd).deleteArtifacts(deepEq(AidlUtils.buildArtifactsPathAsInput(
"/somewhere/app/foo/base.apk", "arm64", mIsInDalvikCache)));
- verify(mArtd).deleteArtifacts(deepEq(AidlUtils.buildArtifactsPath(
+ verify(mArtd).deleteArtifacts(deepEq(AidlUtils.buildArtifactsPathAsInput(
"/somewhere/app/foo/base.apk", "arm", mIsInDalvikCache)));
- verify(mArtd).deleteArtifacts(deepEq(AidlUtils.buildArtifactsPath(
+ verify(mArtd).deleteArtifacts(deepEq(AidlUtils.buildArtifactsPathAsInput(
"/somewhere/app/foo/split_0.apk", "arm64", mIsInDalvikCache)));
- verify(mArtd).deleteArtifacts(deepEq(AidlUtils.buildArtifactsPath(
+ verify(mArtd).deleteArtifacts(deepEq(AidlUtils.buildArtifactsPathAsInput(
"/somewhere/app/foo/split_0.apk", "arm", mIsInDalvikCache)));
verify(mArtd).deleteRuntimeArtifacts(deepEq(AidlUtils.buildRuntimeArtifactsPath(
@@ -546,11 +546,11 @@ public class ArtManagerLocalTest {
PKG_NAME_1, "/somewhere/app/foo/split_0.apk", "arm")));
verify(mArtd).deleteProfile(
- deepEq(AidlUtils.buildProfilePathForSecondaryRef("/data/user/0/foo/1.apk")));
+ deepEq(AidlUtils.buildProfilePathForSecondaryRefAsInput("/data/user/0/foo/1.apk")));
verify(mArtd).deleteProfile(
deepEq(AidlUtils.buildProfilePathForSecondaryCur("/data/user/0/foo/1.apk")));
- verify(mArtd).deleteArtifacts(deepEq(AidlUtils.buildArtifactsPath(
+ verify(mArtd).deleteArtifacts(deepEq(AidlUtils.buildArtifactsPathAsInput(
"/data/user/0/foo/1.apk", "arm64", false /* isInDalvikCache */)));
}
@@ -836,7 +836,8 @@ public class ArtManagerLocalTest {
File tempFile = File.createTempFile("primary", ".prof");
tempFile.deleteOnExit();
- ProfilePath refProfile = AidlUtils.buildProfilePathForPrimaryRef(PKG_NAME_1, "primary");
+ ProfilePath refProfile =
+ AidlUtils.buildProfilePathForPrimaryRefAsInput(PKG_NAME_1, "primary");
String dexPath = "/somewhere/app/foo/base.apk";
when(mArtd.isProfileUsable(deepEq(refProfile), eq(dexPath))).thenReturn(true);
@@ -848,7 +849,8 @@ public class ArtManagerLocalTest {
1 /* userId */, PKG_NAME_1, "primary"))),
isNull(),
deepEq(AidlUtils.buildOutputProfileForPrimary(PKG_NAME_1, "primary",
- Process.SYSTEM_UID, Process.SYSTEM_UID, false /* isPublic */)),
+ Process.SYSTEM_UID, Process.SYSTEM_UID, false /* isPublic */,
+ false /* isPreReboot */)),
deepEq(List.of(dexPath)), deepEq(options)))
.thenAnswer(invocation -> {
try (var writer = new FileWriter(tempFile)) {
@@ -880,7 +882,8 @@ public class ArtManagerLocalTest {
File tempFileForSnapshot = File.createTempFile("primary", ".prof");
tempFileForSnapshot.deleteOnExit();
- ProfilePath refProfile = AidlUtils.buildProfilePathForPrimaryRef(PKG_NAME_1, "primary");
+ ProfilePath refProfile =
+ AidlUtils.buildProfilePathForPrimaryRefAsInput(PKG_NAME_1, "primary");
String dexPath = "/somewhere/app/foo/base.apk";
// Simulate that the reference profile doesn't exist.
@@ -920,7 +923,8 @@ public class ArtManagerLocalTest {
@Test
public void testSnapshotAppProfileFromEmbeddedProfile() throws Exception {
- ProfilePath refProfile = AidlUtils.buildProfilePathForPrimaryRef(PKG_NAME_1, "primary");
+ ProfilePath refProfile =
+ AidlUtils.buildProfilePathForPrimaryRefAsInput(PKG_NAME_1, "primary");
String dexPath = "/somewhere/app/foo/base.apk";
// Simulate that the reference profile doesn't exist.
@@ -937,7 +941,8 @@ public class ArtManagerLocalTest {
@Test
public void testSnapshotAppProfileDisableEmbeddedProfile() throws Exception {
- ProfilePath refProfile = AidlUtils.buildProfilePathForPrimaryRef(PKG_NAME_1, "primary");
+ ProfilePath refProfile =
+ AidlUtils.buildProfilePathForPrimaryRefAsInput(PKG_NAME_1, "primary");
String dexPath = "/somewhere/app/foo/base.apk";
// Simulate that the reference profile doesn't exist.
@@ -959,7 +964,7 @@ public class ArtManagerLocalTest {
@Test
public void testSnapshotAppProfileSplit() throws Exception {
ProfilePath refProfile =
- AidlUtils.buildProfilePathForPrimaryRef(PKG_NAME_1, "split_0.split");
+ AidlUtils.buildProfilePathForPrimaryRefAsInput(PKG_NAME_1, "split_0.split");
String dexPath = "/somewhere/app/foo/split_0.apk";
when(mArtd.isProfileUsable(deepEq(refProfile), eq(dexPath))).thenReturn(true);
@@ -971,7 +976,8 @@ public class ArtManagerLocalTest {
1 /* userId */, PKG_NAME_1, "split_0.split"))),
isNull(),
deepEq(AidlUtils.buildOutputProfileForPrimary(PKG_NAME_1, "split_0.split",
- Process.SYSTEM_UID, Process.SYSTEM_UID, false /* isPublic */)),
+ Process.SYSTEM_UID, Process.SYSTEM_UID, false /* isPublic */,
+ false /* isPreReboot */)),
deepEq(List.of(dexPath)), any()))
.thenReturn(false);
@@ -1049,27 +1055,28 @@ public class ArtManagerLocalTest {
when(mArtd.mergeProfiles(
inAnyOrderDeepEquals(
- AidlUtils.buildProfilePathForPrimaryRef("android", "primary"),
+ AidlUtils.buildProfilePathForPrimaryRefAsInput("android", "primary"),
AidlUtils.buildProfilePathForPrimaryCur(
0 /* userId */, "android", "primary"),
AidlUtils.buildProfilePathForPrimaryCur(
1 /* userId */, "android", "primary"),
- AidlUtils.buildProfilePathForPrimaryRef(PKG_NAME_1, "primary"),
+ AidlUtils.buildProfilePathForPrimaryRefAsInput(PKG_NAME_1, "primary"),
AidlUtils.buildProfilePathForPrimaryCur(
0 /* userId */, PKG_NAME_1, "primary"),
AidlUtils.buildProfilePathForPrimaryCur(
1 /* userId */, PKG_NAME_1, "primary"),
- AidlUtils.buildProfilePathForPrimaryRef(PKG_NAME_1, "split_0.split"),
+ AidlUtils.buildProfilePathForPrimaryRefAsInput(
+ PKG_NAME_1, "split_0.split"),
AidlUtils.buildProfilePathForPrimaryCur(
0 /* userId */, PKG_NAME_1, "split_0.split"),
AidlUtils.buildProfilePathForPrimaryCur(
1 /* userId */, PKG_NAME_1, "split_0.split"),
- AidlUtils.buildProfilePathForPrimaryRef(PKG_NAME_2, "primary"),
+ AidlUtils.buildProfilePathForPrimaryRefAsInput(PKG_NAME_2, "primary"),
AidlUtils.buildProfilePathForPrimaryCur(
0 /* userId */, PKG_NAME_2, "primary"),
AidlUtils.buildProfilePathForPrimaryCur(
1 /* userId */, PKG_NAME_2, "primary"),
- AidlUtils.buildProfilePathForPrimaryRef(
+ AidlUtils.buildProfilePathForPrimaryRefAsInput(
PKG_NAME_HIBERNATING, "primary"),
AidlUtils.buildProfilePathForPrimaryCur(
0 /* userId */, PKG_NAME_HIBERNATING, "primary"),
@@ -1077,7 +1084,8 @@ public class ArtManagerLocalTest {
1 /* userId */, PKG_NAME_HIBERNATING, "primary")),
isNull(),
deepEq(AidlUtils.buildOutputProfileForPrimary("android", "primary",
- Process.SYSTEM_UID, Process.SYSTEM_UID, false /* isPublic */)),
+ Process.SYSTEM_UID, Process.SYSTEM_UID, false /* isPublic */,
+ false /* isPreReboot */)),
deepEq(List.of("bcp0", "bcp1", "sscp0", "sscp1", "sssj0", "sssj1")),
deepEq(options)))
.thenReturn(false); // A non-empty merge is tested in `testSnapshotAppProfile`.
@@ -1144,25 +1152,27 @@ public class ArtManagerLocalTest {
mArtManagerLocal.cleanup(mSnapshot);
verify(mArtd).cleanup(
- inAnyOrderDeepEquals(AidlUtils.buildProfilePathForPrimaryRef(PKG_NAME_1, "primary"),
+ inAnyOrderDeepEquals(
+ AidlUtils.buildProfilePathForPrimaryRefAsInput(PKG_NAME_1, "primary"),
AidlUtils.buildProfilePathForPrimaryCur(
0 /* userId */, PKG_NAME_1, "primary"),
AidlUtils.buildProfilePathForPrimaryCur(
1 /* userId */, PKG_NAME_1, "primary"),
- AidlUtils.buildProfilePathForPrimaryRef(PKG_NAME_1, "split_0.split"),
+ AidlUtils.buildProfilePathForPrimaryRefAsInput(PKG_NAME_1, "split_0.split"),
AidlUtils.buildProfilePathForPrimaryCur(
0 /* userId */, PKG_NAME_1, "split_0.split"),
AidlUtils.buildProfilePathForPrimaryCur(
1 /* userId */, PKG_NAME_1, "split_0.split"),
- AidlUtils.buildProfilePathForSecondaryRef("/data/user/0/foo/1.apk"),
+ AidlUtils.buildProfilePathForSecondaryRefAsInput("/data/user/0/foo/1.apk"),
AidlUtils.buildProfilePathForSecondaryCur("/data/user/0/foo/1.apk")),
- inAnyOrderDeepEquals(AidlUtils.buildArtifactsPath("/somewhere/app/foo/base.apk",
- "arm64", false /* isInDalvikCache */),
- AidlUtils.buildArtifactsPath(
+ inAnyOrderDeepEquals(
+ AidlUtils.buildArtifactsPathAsInput("/somewhere/app/foo/base.apk", "arm64",
+ false /* isInDalvikCache */),
+ AidlUtils.buildArtifactsPathAsInput(
"/data/user/0/foo/1.apk", "arm64", false /* isInDalvikCache */),
- AidlUtils.buildArtifactsPath("/somewhere/app/foo/split_0.apk", "arm64",
- true /* isInDalvikCache */)),
- inAnyOrderDeepEquals(VdexPath.artifactsPath(AidlUtils.buildArtifactsPath(
+ AidlUtils.buildArtifactsPathAsInput("/somewhere/app/foo/split_0.apk",
+ "arm64", true /* isInDalvikCache */)),
+ inAnyOrderDeepEquals(VdexPath.artifactsPath(AidlUtils.buildArtifactsPathAsInput(
"/somewhere/app/foo/split_0.apk", "arm", false /* isInDalvikCache */))),
inAnyOrderDeepEquals(AidlUtils.buildRuntimeArtifactsPath(
PKG_NAME_1, "/somewhere/app/foo/split_0.apk", "arm64"),
@@ -1227,14 +1237,14 @@ public class ArtManagerLocalTest {
.getDexoptStatus(eq("/somewhere/app/foo/base.apk"), eq("arm"), any());
// These are counted as TYPE_DEXOPT_ARTIFACT.
- doReturn(1l << 0).when(mArtd).getArtifactsSize(deepEq(AidlUtils.buildArtifactsPath(
+ doReturn(1l << 0).when(mArtd).getArtifactsSize(deepEq(AidlUtils.buildArtifactsPathAsInput(
"/somewhere/app/foo/base.apk", "arm64", false /* isInDalvikCache */)));
- doReturn(1l << 1).when(mArtd).getArtifactsSize(deepEq(AidlUtils.buildArtifactsPath(
+ doReturn(1l << 1).when(mArtd).getArtifactsSize(deepEq(AidlUtils.buildArtifactsPathAsInput(
"/data/user/0/foo/1.apk", "arm64", false /* isInDalvikCache */)));
- doReturn(1l << 2).when(mArtd).getArtifactsSize(deepEq(AidlUtils.buildArtifactsPath(
+ doReturn(1l << 2).when(mArtd).getArtifactsSize(deepEq(AidlUtils.buildArtifactsPathAsInput(
"/somewhere/app/foo/split_0.apk", "arm64", true /* isInDalvikCache */)));
doReturn(1l << 3).when(mArtd).getVdexFileSize(
- deepEq(VdexPath.artifactsPath(AidlUtils.buildArtifactsPath(
+ deepEq(VdexPath.artifactsPath(AidlUtils.buildArtifactsPathAsInput(
"/somewhere/app/foo/split_0.apk", "arm", false /* isInDalvikCache */))));
doReturn(1l << 4).when(mArtd).getRuntimeArtifactsSize(
deepEq(AidlUtils.buildRuntimeArtifactsPath(
@@ -1250,11 +1260,11 @@ public class ArtManagerLocalTest {
// These are counted as TYPE_REF_PROFILE.
doReturn(1l << 6).when(mArtd).getProfileSize(
- deepEq(AidlUtils.buildProfilePathForPrimaryRef(PKG_NAME_1, "primary")));
- doReturn(1l << 7).when(mArtd).getProfileSize(
- deepEq(AidlUtils.buildProfilePathForPrimaryRef(PKG_NAME_1, "split_0.split")));
+ deepEq(AidlUtils.buildProfilePathForPrimaryRefAsInput(PKG_NAME_1, "primary")));
+ doReturn(1l << 7).when(mArtd).getProfileSize(deepEq(
+ AidlUtils.buildProfilePathForPrimaryRefAsInput(PKG_NAME_1, "split_0.split")));
doReturn(1l << 8).when(mArtd).getProfileSize(
- deepEq(AidlUtils.buildProfilePathForSecondaryRef("/data/user/0/foo/1.apk")));
+ deepEq(AidlUtils.buildProfilePathForSecondaryRefAsInput("/data/user/0/foo/1.apk")));
long expectedRefProfileSize = (1l << 6) + (1l << 7) + (1l << 8);
int expectedGetProfileSizeCalls = 3;
@@ -1278,15 +1288,16 @@ public class ArtManagerLocalTest {
// These are counted as TYPE_DEXOPT_ARTIFACT.
// Dexopt artifacts of secondary dex files.
- doReturn(1l << 12).when(mArtd).getArtifactsSize(deepEq(AidlUtils.buildArtifactsPath(
- "/data/user/1/foo/1.apk", "arm64", false /* isInDalvikCache */)));
+ doReturn(1l << 12).when(mArtd).getArtifactsSize(
+ deepEq(AidlUtils.buildArtifactsPathAsInput(
+ "/data/user/1/foo/1.apk", "arm64", false /* isInDalvikCache */)));
expectedDexoptArtifactSize += (1l << 12);
expectedGetArtifactsSizeCalls += 1;
// These are counted as TYPE_REF_PROFILE.
// Reference profiles of secondary dex files.
- doReturn(1l << 13).when(mArtd).getProfileSize(
- deepEq(AidlUtils.buildProfilePathForSecondaryRef("/data/user/1/foo/1.apk")));
+ doReturn(1l << 13).when(mArtd).getProfileSize(deepEq(
+ AidlUtils.buildProfilePathForSecondaryRefAsInput("/data/user/1/foo/1.apk")));
expectedRefProfileSize += (1l << 13);
expectedGetProfileSizeCalls += 1;
diff --git a/libartservice/service/javatests/com/android/server/art/DexUseManagerTest.java b/libartservice/service/javatests/com/android/server/art/DexUseManagerTest.java
index 5662090aeb..5bd2edc6d2 100644
--- a/libartservice/service/javatests/com/android/server/art/DexUseManagerTest.java
+++ b/libartservice/service/javatests/com/android/server/art/DexUseManagerTest.java
@@ -166,6 +166,7 @@ public class DexUseManagerTest {
.thenAnswer(invocation -> mMockClock.createScheduledExecutor());
lenient().when(mInjector.getContext()).thenReturn(mContext);
lenient().when(mInjector.getAllPackageNames()).thenReturn(mPackageStates.keySet());
+ lenient().when(mInjector.isPreReboot()).thenReturn(false);
mDexUseManager = new DexUseManagerLocal(mInjector);
mDexUseManager.systemReady();
@@ -774,6 +775,13 @@ public class DexUseManagerTest {
true /* isUsedByOtherApps */, mDefaultFileVisibility));
}
+ @Test(expected = IllegalStateException.class)
+ public void testPreRebootNoUpdate() throws Exception {
+ when(mInjector.isPreReboot()).thenReturn(true);
+ mDexUseManager.notifyDexContainersLoaded(
+ mSnapshot, OWNING_PKG_NAME, Map.of(BASE_APK, "CLC"));
+ }
+
private AndroidPackage createPackage(String packageName) {
AndroidPackage pkg = mock(AndroidPackage.class);
lenient().when(pkg.getStorageUuid()).thenReturn(StorageManager.UUID_DEFAULT);
diff --git a/libartservice/service/javatests/com/android/server/art/PrimaryDexopterParameterizedTest.java b/libartservice/service/javatests/com/android/server/art/PrimaryDexopterParameterizedTest.java
index 8f7befb957..30595aafd2 100644
--- a/libartservice/service/javatests/com/android/server/art/PrimaryDexopterParameterizedTest.java
+++ b/libartservice/service/javatests/com/android/server/art/PrimaryDexopterParameterizedTest.java
@@ -195,6 +195,12 @@ public class PrimaryDexopterParameterizedTest extends PrimaryDexopterTestBase {
params.mExpectedCompilerFilter = "verify";
list.add(params);
+ params = new Params();
+ params.mIsPreReboot = true;
+ params.mExpectedOutputIsPreReboot = true;
+ params.mExpectedDeletesRuntimeArtifacts = false;
+ list.add(params);
+
return list;
}
@@ -204,6 +210,7 @@ public class PrimaryDexopterParameterizedTest extends PrimaryDexopterTestBase {
lenient().when(mInjector.isSystemUiPackage(any())).thenReturn(mParams.mIsSystemUi);
lenient().when(mInjector.isLauncherPackage(any())).thenReturn(mParams.mIsLauncher);
+ lenient().when(mInjector.isPreReboot()).thenReturn(mParams.mIsPreReboot);
lenient()
.when(SystemProperties.getBoolean(eq("dalvik.vm.always_debuggable"), anyBoolean()))
@@ -285,7 +292,8 @@ public class PrimaryDexopterParameterizedTest extends PrimaryDexopterTestBase {
400 /* cpuTimeMs */, 30000 /* sizeBytes */, 32000 /* sizeBeforeBytes */))
.when(mArtd)
.dexopt(deepEq(buildOutputArtifacts("/somewhere/app/foo/base.apk", "arm64",
- mParams.mIsInDalvikCache, permissionSettings)),
+ mParams.mIsInDalvikCache, permissionSettings,
+ mParams.mExpectedOutputIsPreReboot)),
eq("/somewhere/app/foo/base.apk"), eq("arm64"), eq("PCL[]"),
eq(mParams.mExpectedCompilerFilter), any() /* profile */,
isNull() /* inputVdex */, isNull() /* dmFile */,
@@ -299,7 +307,8 @@ public class PrimaryDexopterParameterizedTest extends PrimaryDexopterTestBase {
doThrow(ServiceSpecificException.class)
.when(mArtd)
.dexopt(deepEq(buildOutputArtifacts("/somewhere/app/foo/base.apk", "arm",
- mParams.mIsInDalvikCache, permissionSettings)),
+ mParams.mIsInDalvikCache, permissionSettings,
+ mParams.mExpectedOutputIsPreReboot)),
eq("/somewhere/app/foo/base.apk"), eq("arm"), eq("PCL[]"),
eq(mParams.mExpectedCompilerFilter), any() /* profile */,
isNull() /* inputVdex */, isNull() /* dmFile */,
@@ -320,18 +329,23 @@ public class PrimaryDexopterParameterizedTest extends PrimaryDexopterTestBase {
200 /* cpuTimeMs */, 10000 /* sizeBytes */, 0 /* sizeBeforeBytes */))
.when(mArtd)
.dexopt(deepEq(buildOutputArtifacts("/somewhere/app/foo/split_0.apk", "arm",
- mParams.mIsInDalvikCache, permissionSettings)),
+ mParams.mIsInDalvikCache, permissionSettings,
+ mParams.mExpectedOutputIsPreReboot)),
eq("/somewhere/app/foo/split_0.apk"), eq("arm"), eq("PCL[base.apk]"),
eq(mParams.mExpectedCompilerFilter), any() /* profile */,
isNull() /* inputVdex */, isNull() /* dmFile */,
eq(PriorityClass.INTERACTIVE), argThat(dexoptOptionsMatcher), any());
- // Only delete runtime artifacts for successful dexopt operations, namely the first one and
- // the fourth one.
- doReturn(1l).when(mArtd).deleteRuntimeArtifacts(deepEq(AidlUtils.buildRuntimeArtifactsPath(
- PKG_NAME, "/somewhere/app/foo/base.apk", "arm64")));
- doReturn(1l).when(mArtd).deleteRuntimeArtifacts(deepEq(AidlUtils.buildRuntimeArtifactsPath(
- PKG_NAME, "/somewhere/app/foo/split_0.apk", "arm")));
+ if (mParams.mExpectedDeletesRuntimeArtifacts) {
+ // Only delete runtime artifacts for successful dexopt operations, namely the first one
+ // and the fourth one.
+ doReturn(1l).when(mArtd).deleteRuntimeArtifacts(
+ deepEq(AidlUtils.buildRuntimeArtifactsPath(
+ PKG_NAME, "/somewhere/app/foo/base.apk", "arm64")));
+ doReturn(1l).when(mArtd).deleteRuntimeArtifacts(
+ deepEq(AidlUtils.buildRuntimeArtifactsPath(
+ PKG_NAME, "/somewhere/app/foo/split_0.apk", "arm")));
+ }
assertThat(mPrimaryDexopter.dexopt())
.comparingElementsUsing(TestingUtils.<DexContainerFileDexoptResult>deepEquality())
@@ -360,6 +374,10 @@ public class PrimaryDexopterParameterizedTest extends PrimaryDexopterTestBase {
verify(mArtd, times(3))
.dexopt(any(), any(), any(), any(), any(), any(), any(), any(), anyInt(), any(),
any());
+
+ if (!mParams.mExpectedDeletesRuntimeArtifacts) {
+ verify(mArtd, times(0)).deleteRuntimeArtifacts(any());
+ }
}
private static class Params {
@@ -379,6 +397,7 @@ public class PrimaryDexopterParameterizedTest extends PrimaryDexopterTestBase {
public boolean mShouldDowngrade = false;
public boolean mSkipIfStorageLow = false;
public boolean mIgnoreProfile = false;
+ public boolean mIsPreReboot = false;
// System properties.
public boolean mAlwaysDebuggable = false;
@@ -390,6 +409,8 @@ public class PrimaryDexopterParameterizedTest extends PrimaryDexopterTestBase {
| DexoptTrigger.PRIMARY_BOOT_IMAGE_BECOMES_USABLE | DexoptTrigger.NEED_EXTRACTION;
public boolean mExpectedIsDebuggable = false;
public boolean mExpectedIsHiddenApiPolicyEnabled = true;
+ public boolean mExpectedOutputIsPreReboot = false;
+ public boolean mExpectedDeletesRuntimeArtifacts = true;
public String toString() {
return String.format("isInDalvikCache=%b,"
@@ -405,19 +426,24 @@ public class PrimaryDexopterParameterizedTest extends PrimaryDexopterTestBase {
+ "shouldDowngrade=%b,"
+ "skipIfStorageLow=%b,"
+ "ignoreProfile=%b,"
+ + "isPreReboot=%b,"
+ "alwaysDebuggable=%b"
+ " => "
+ "expectedCallbackInputCompilerFilter=%s,"
+ "expectedCompilerFilter=%s,"
+ "expectedDexoptTrigger=%d,"
+ "expectedIsDebuggable=%b,"
- + "expectedIsHiddenApiPolicyEnabled=%b",
+ + "expectedIsHiddenApiPolicyEnabled=%b,"
+ + "expectedOutputIsPreReboot=%b,"
+ + "expectedDeleteRuntimeArtifacts=%b",
mIsInDalvikCache, mHiddenApiEnforcementPolicy, mIsVmSafeMode, mIsDebuggable,
mIsSystemUi, mIsLauncher, mIsUseEmbeddedDex, mRequestedCompilerFilter,
mCallbackReturnedCompilerFilter, mForce, mShouldDowngrade, mSkipIfStorageLow,
- mIgnoreProfile, mAlwaysDebuggable, mExpectedCallbackInputCompilerFilter,
- mExpectedCompilerFilter, mExpectedDexoptTrigger, mExpectedIsDebuggable,
- mExpectedIsHiddenApiPolicyEnabled);
+ mIgnoreProfile, mIsPreReboot, mAlwaysDebuggable,
+ mExpectedCallbackInputCompilerFilter, mExpectedCompilerFilter,
+ mExpectedDexoptTrigger, mExpectedIsDebuggable,
+ mExpectedIsHiddenApiPolicyEnabled, mExpectedOutputIsPreReboot,
+ mExpectedDeletesRuntimeArtifacts);
}
}
}
diff --git a/libartservice/service/javatests/com/android/server/art/PrimaryDexopterTest.java b/libartservice/service/javatests/com/android/server/art/PrimaryDexopterTest.java
index a58add5f30..beb8c1eaf4 100644
--- a/libartservice/service/javatests/com/android/server/art/PrimaryDexopterTest.java
+++ b/libartservice/service/javatests/com/android/server/art/PrimaryDexopterTest.java
@@ -71,18 +71,20 @@ public class PrimaryDexopterTest extends PrimaryDexopterTestBase {
private final String mDexPath = "/somewhere/app/foo/base.apk";
private final String mDmPath = "/somewhere/app/foo/base.dm";
private final ProfilePath mRefProfile =
- AidlUtils.buildProfilePathForPrimaryRef(PKG_NAME, "primary");
+ AidlUtils.buildProfilePathForPrimaryRefAsInput(PKG_NAME, "primary");
private final ProfilePath mPrebuiltProfile = AidlUtils.buildProfilePathForPrebuilt(mDexPath);
private final ProfilePath mDmProfile = AidlUtils.buildProfilePathForDm(mDexPath);
private final DexMetadataPath mDmFile = AidlUtils.buildDexMetadataPath(mDexPath);
- private final OutputProfile mPublicOutputProfile = AidlUtils.buildOutputProfileForPrimary(
- PKG_NAME, "primary", Process.SYSTEM_UID, SHARED_GID, true /* isOtherReadable */);
- private final OutputProfile mPrivateOutputProfile = AidlUtils.buildOutputProfileForPrimary(
- PKG_NAME, "primary", Process.SYSTEM_UID, SHARED_GID, false /* isOtherReadable */);
+ private final OutputProfile mPublicOutputProfile =
+ AidlUtils.buildOutputProfileForPrimary(PKG_NAME, "primary", Process.SYSTEM_UID,
+ SHARED_GID, true /* isOtherReadable */, false /* isPreReboot */);
+ private final OutputProfile mPrivateOutputProfile =
+ AidlUtils.buildOutputProfileForPrimary(PKG_NAME, "primary", Process.SYSTEM_UID,
+ SHARED_GID, false /* isOtherReadable */, false /* isPreReboot */);
private final String mSplit0DexPath = "/somewhere/app/foo/split_0.apk";
private final ProfilePath mSplit0RefProfile =
- AidlUtils.buildProfilePathForPrimaryRef(PKG_NAME, "split_0.split");
+ AidlUtils.buildProfilePathForPrimaryRefAsInput(PKG_NAME, "split_0.split");
private final int mDefaultDexoptTrigger = DexoptTrigger.COMPILER_FILTER_IS_BETTER
| DexoptTrigger.PRIMARY_BOOT_IMAGE_BECOMES_USABLE | DexoptTrigger.NEED_EXTRACTION;
@@ -163,7 +165,7 @@ public class PrimaryDexopterTest extends PrimaryDexopterTestBase {
doReturn(mArtdDexoptResult)
.when(mArtd)
.dexopt(any(), eq(mDexPath), eq("arm"), any(), any(), any(),
- deepEq(VdexPath.artifactsPath(AidlUtils.buildArtifactsPath(
+ deepEq(VdexPath.artifactsPath(AidlUtils.buildArtifactsPathAsInput(
mDexPath, "arm", true /* isInDalvikCache */))),
any(), anyInt(), any(), any());
@@ -174,7 +176,7 @@ public class PrimaryDexopterTest extends PrimaryDexopterTestBase {
doReturn(mArtdDexoptResult)
.when(mArtd)
.dexopt(any(), eq(mSplit0DexPath), eq("arm64"), any(), any(), any(),
- deepEq(VdexPath.artifactsPath(AidlUtils.buildArtifactsPath(
+ deepEq(VdexPath.artifactsPath(AidlUtils.buildArtifactsPathAsInput(
mSplit0DexPath, "arm64", false /* isInDalvikCache */))),
any(), anyInt(), any(), any());
@@ -303,8 +305,7 @@ public class PrimaryDexopterTest extends PrimaryDexopterTestBase {
verifyEmbeddedProfileNotUsed(mDexPath);
}
- @Test
- public void testDexoptMergesProfiles() throws Exception {
+ private void checkDexoptMergesProfiles() throws Exception {
setPackageInstalledForUserIds(0, 2);
when(mArtd.mergeProfiles(any(), any(), any(), any(), any())).thenReturn(true);
@@ -340,14 +341,30 @@ public class PrimaryDexopterTest extends PrimaryDexopterTestBase {
false /* isOtherReadable */);
inOrder.verify(mArtd).commitTmpProfile(deepEq(mPrivateOutputProfile.profilePath));
+ }
- inOrder.verify(mArtd).deleteProfile(deepEq(
+ @Test
+ public void testDexoptMergesProfiles() throws Exception {
+ checkDexoptMergesProfiles();
+
+ verify(mArtd).deleteProfile(deepEq(
AidlUtils.buildProfilePathForPrimaryCur(0 /* userId */, PKG_NAME, "primary")));
- inOrder.verify(mArtd).deleteProfile(deepEq(
+ verify(mArtd).deleteProfile(deepEq(
AidlUtils.buildProfilePathForPrimaryCur(2 /* userId */, PKG_NAME, "primary")));
}
@Test
+ public void testDexoptMergesProfilesPreReboot() throws Exception {
+ when(mInjector.isPreReboot()).thenReturn(true);
+ mPublicOutputProfile.profilePath.finalPath.getForPrimary().isPreReboot = true;
+ mPrivateOutputProfile.profilePath.finalPath.getForPrimary().isPreReboot = true;
+
+ checkDexoptMergesProfiles();
+
+ verify(mArtd, never()).deleteProfile(any());
+ }
+
+ @Test
public void testDexoptMergesProfilesMergeFailed() throws Exception {
setPackageInstalledForUserIds(0, 2);
@@ -397,8 +414,7 @@ public class PrimaryDexopterTest extends PrimaryDexopterTestBase {
mPrimaryDexopter.dexopt();
}
- @Test
- public void testDexoptUsesDmProfile() throws Exception {
+ private void checkDexoptUsesDmProfile() throws Exception {
makeProfileUsable(mDmProfile);
makeEmbeddedProfileUsable(mDexPath);
@@ -420,6 +436,20 @@ public class PrimaryDexopterTest extends PrimaryDexopterTestBase {
verifyEmbeddedProfileNotUsed(mDexPath);
}
+ @Test
+ public void testDexoptUsesDmProfile() throws Exception {
+ checkDexoptUsesDmProfile();
+ }
+
+ @Test
+ public void testDexoptUsesDmProfilePreReboot() throws Exception {
+ when(mInjector.isPreReboot()).thenReturn(true);
+ mPublicOutputProfile.profilePath.finalPath.getForPrimary().isPreReboot = true;
+ mPrivateOutputProfile.profilePath.finalPath.getForPrimary().isPreReboot = true;
+
+ checkDexoptUsesDmProfile();
+ }
+
private void checkDexoptUsesEmbeddedProfile() throws Exception {
makeEmbeddedProfileUsable(mDexPath);
@@ -501,6 +531,15 @@ public class PrimaryDexopterTest extends PrimaryDexopterTestBase {
}
@Test
+ public void testDexoptUsesEmbeddedProfilePreReboot() throws Exception {
+ when(mInjector.isPreReboot()).thenReturn(true);
+ mPublicOutputProfile.profilePath.finalPath.getForPrimary().isPreReboot = true;
+ mPrivateOutputProfile.profilePath.finalPath.getForPrimary().isPreReboot = true;
+
+ checkDexoptUsesEmbeddedProfile();
+ }
+
+ @Test
public void testDexoptExternalProfileErrors() throws Exception {
// Having no profile should not be reported.
// Having a bad profile should be reported.
diff --git a/libartservice/service/javatests/com/android/server/art/PrimaryDexopterTestBase.java b/libartservice/service/javatests/com/android/server/art/PrimaryDexopterTestBase.java
index 5e26835da2..3105e4e51b 100644
--- a/libartservice/service/javatests/com/android/server/art/PrimaryDexopterTestBase.java
+++ b/libartservice/service/javatests/com/android/server/art/PrimaryDexopterTestBase.java
@@ -92,6 +92,7 @@ public class PrimaryDexopterTestBase {
lenient().when(mInjector.getArtVersion()).thenReturn(ART_VERSION);
lenient().when(mInjector.getConfig()).thenReturn(mConfig);
lenient().when(mInjector.getDexMetadataHelper()).thenReturn(mDexMetadataHelper);
+ lenient().when(mInjector.isPreReboot()).thenReturn(false);
lenient()
.when(SystemProperties.get("dalvik.vm.systemuicompilerfilter"))
diff --git a/libartservice/service/javatests/com/android/server/art/SecondaryDexopterTest.java b/libartservice/service/javatests/com/android/server/art/SecondaryDexopterTest.java
index 13ff28a908..07dd07dae7 100644
--- a/libartservice/service/javatests/com/android/server/art/SecondaryDexopterTest.java
+++ b/libartservice/service/javatests/com/android/server/art/SecondaryDexopterTest.java
@@ -81,12 +81,16 @@ public class SecondaryDexopterTest {
.setFlags(ArtFlags.FLAG_FOR_PRIMARY_DEX | ArtFlags.FLAG_FOR_SECONDARY_DEX)
.build();
- private final ProfilePath mDex1RefProfile = AidlUtils.buildProfilePathForSecondaryRef(DEX_1);
+ private final ProfilePath mDex1RefProfile =
+ AidlUtils.buildProfilePathForSecondaryRefAsInput(DEX_1);
private final ProfilePath mDex1CurProfile = AidlUtils.buildProfilePathForSecondaryCur(DEX_1);
- private final ProfilePath mDex2RefProfile = AidlUtils.buildProfilePathForSecondaryRef(DEX_2);
- private final ProfilePath mDex3RefProfile = AidlUtils.buildProfilePathForSecondaryRef(DEX_3);
+ private final ProfilePath mDex2RefProfile =
+ AidlUtils.buildProfilePathForSecondaryRefAsInput(DEX_2);
+ private final ProfilePath mDex3RefProfile =
+ AidlUtils.buildProfilePathForSecondaryRefAsInput(DEX_3);
private final OutputProfile mDex1PrivateOutputProfile =
- AidlUtils.buildOutputProfileForSecondary(DEX_1, UID, UID, false /* isOtherReadable */);
+ AidlUtils.buildOutputProfileForSecondary(
+ DEX_1, UID, UID, false /* isOtherReadable */, false /* isPreReboot */);
private final int mDefaultDexoptTrigger = DexoptTrigger.COMPILER_FILTER_IS_BETTER
| DexoptTrigger.PRIMARY_BOOT_IMAGE_BECOMES_USABLE | DexoptTrigger.NEED_EXTRACTION;
@@ -322,8 +326,8 @@ public class SecondaryDexopterTest {
private void checkDexoptWithPrivateProfile(IArtd artd, String dexPath, String isa,
ProfilePath profile, String classLoaderContext) throws Exception {
PermissionSettings permissionSettings = buildPermissionSettings(false /* isPublic */);
- OutputArtifacts outputArtifacts = AidlUtils.buildOutputArtifacts(
- dexPath, isa, false /* isInDalvikCache */, permissionSettings);
+ OutputArtifacts outputArtifacts = AidlUtils.buildOutputArtifacts(dexPath, isa,
+ false /* isInDalvikCache */, permissionSettings, false /* isPreReboot */);
artd.dexopt(deepEq(outputArtifacts), eq(dexPath), eq(isa), eq(classLoaderContext),
eq("speed-profile"), deepEq(profile), any(), isNull() /* dmFile */, anyInt(),
argThat(dexoptOptions -> dexoptOptions.generateAppImage == true), any());
@@ -332,8 +336,8 @@ public class SecondaryDexopterTest {
private void checkDexoptWithNoProfile(IArtd artd, String dexPath, String isa,
String compilerFilter, String classLoaderContext, boolean isPublic) throws Exception {
PermissionSettings permissionSettings = buildPermissionSettings(isPublic);
- OutputArtifacts outputArtifacts = AidlUtils.buildOutputArtifacts(
- dexPath, isa, false /* isInDalvikCache */, permissionSettings);
+ OutputArtifacts outputArtifacts = AidlUtils.buildOutputArtifacts(dexPath, isa,
+ false /* isInDalvikCache */, permissionSettings, false /* isPreReboot */);
artd.dexopt(deepEq(outputArtifacts), eq(dexPath), eq(isa), eq(classLoaderContext),
eq(compilerFilter), isNull(), any(), isNull() /* dmFile */, anyInt(),
argThat(dexoptOptions -> dexoptOptions.generateAppImage == false), any());