summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Dmitrii Ishcheikin <ishcheikin@google.com> 2024-06-18 16:59:52 +0000
committer Dmitrii Ishcheikin <ishcheikin@google.com> 2024-07-03 14:55:10 +0000
commitbfb7f772d13b28d4cde86692b92547dddd06c5d2 (patch)
tree41a9e1e3009e7400b88b2dec86f2427cbe2bbf71
parentc1d49fdab3302ed1222f7b2ee1e3e3ccd7df892d (diff)
Add support for multiple dirty-image-objects files
Allow dex2oat to have multiple --dirty-image-objects inputs. Modify odrefresh to use dirty-image-objects from ART APEX, if present. Add test to ensure that odrefresh passes all dirty-image-objects files to dex2oat. Bug: 346990440 Test: m test-art-host-gtest-art_dex2oat_tests Test: atest art_standalone_odrefresh_tests Change-Id: I11aa8d139577d34e6f4f60321d7344cc6b89526a
-rw-r--r--dex2oat/dex2oat.cc45
-rw-r--r--dex2oat/dex2oat_image_test.cc22
-rw-r--r--dex2oat/dex2oat_options.cc4
-rw-r--r--dex2oat/dex2oat_options.def4
-rw-r--r--odrefresh/odrefresh.cc28
-rw-r--r--odrefresh/odrefresh_test.cc57
6 files changed, 118 insertions, 42 deletions
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index 076461c267..f1d70fb7ff 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -530,8 +530,6 @@ class Dex2Oat final {
image_base_(0U),
image_storage_mode_(ImageHeader::kStorageModeUncompressed),
passes_to_run_filename_(nullptr),
- dirty_image_objects_filename_(nullptr),
- dirty_image_objects_fd_(-1),
is_host_(false),
elf_writers_(),
oat_writers_(),
@@ -844,7 +842,7 @@ class Dex2Oat final {
}
}
- if (dirty_image_objects_filename_ != nullptr && dirty_image_objects_fd_ != -1) {
+ if (!dirty_image_objects_filenames_.empty() && !dirty_image_objects_fds_.empty()) {
Usage("--dirty-image-objects and --dirty-image-objects-fd should not be both specified");
}
@@ -1110,8 +1108,8 @@ class Dex2Oat final {
AssignIfExists(args, M::AppImageFileFd, &app_image_fd_);
AssignIfExists(args, M::NoInlineFrom, &no_inline_from_string_);
AssignIfExists(args, M::ClasspathDir, &classpath_dir_);
- AssignIfExists(args, M::DirtyImageObjects, &dirty_image_objects_filename_);
- AssignIfExists(args, M::DirtyImageObjectsFd, &dirty_image_objects_fd_);
+ AssignIfExists(args, M::DirtyImageObjects, &dirty_image_objects_filenames_);
+ AssignIfExists(args, M::DirtyImageObjectsFd, &dirty_image_objects_fds_);
AssignIfExists(args, M::ImageFormat, &image_storage_mode_);
AssignIfExists(args, M::CompilationReason, &compilation_reason_);
AssignTrueIfExists(args, M::CheckLinkageConditions, &check_linkage_conditions_);
@@ -2529,23 +2527,26 @@ class Dex2Oat final {
}
bool PrepareDirtyObjects() {
- if (dirty_image_objects_fd_ != -1) {
- dirty_image_objects_ =
- ReadCommentedInputFromFd<std::vector<std::string>>(dirty_image_objects_fd_, nullptr);
+ if (!dirty_image_objects_fds_.empty()) {
+ dirty_image_objects_ = std::make_unique<std::vector<std::string>>();
+ for (int fd : dirty_image_objects_fds_) {
+ if (!ReadCommentedInputFromFd(fd, nullptr, dirty_image_objects_.get())) {
+ LOG(ERROR) << "Failed to create list of dirty objects from fd " << fd;
+ return false;
+ }
+ }
// Close since we won't need it again.
- close(dirty_image_objects_fd_);
- dirty_image_objects_fd_ = -1;
- if (dirty_image_objects_ == nullptr) {
- LOG(ERROR) << "Failed to create list of dirty objects from fd " << dirty_image_objects_fd_;
- return false;
+ for (int fd : dirty_image_objects_fds_) {
+ close(fd);
}
- } else if (dirty_image_objects_filename_ != nullptr) {
- dirty_image_objects_ = ReadCommentedInputFromFile<std::vector<std::string>>(
- dirty_image_objects_filename_, nullptr);
- if (dirty_image_objects_ == nullptr) {
- LOG(ERROR) << "Failed to create list of dirty objects from '"
- << dirty_image_objects_filename_ << "'";
- return false;
+ dirty_image_objects_fds_.clear();
+ } else {
+ dirty_image_objects_ = std::make_unique<std::vector<std::string>>();
+ for (const std::string& file : preloaded_classes_files_) {
+ if (!ReadCommentedInputFromFile(file.c_str(), nullptr, dirty_image_objects_.get())) {
+ LOG(ERROR) << "Failed to create list of dirty objects from '" << file << "'";
+ return false;
+ }
}
}
return true;
@@ -2947,8 +2948,8 @@ class Dex2Oat final {
uintptr_t image_base_;
ImageHeader::StorageMode image_storage_mode_;
const char* passes_to_run_filename_;
- const char* dirty_image_objects_filename_;
- int dirty_image_objects_fd_;
+ std::vector<std::string> dirty_image_objects_filenames_;
+ std::vector<int> dirty_image_objects_fds_;
std::unique_ptr<std::vector<std::string>> dirty_image_objects_;
std::unique_ptr<std::vector<std::string>> passes_to_run_;
bool is_host_;
diff --git a/dex2oat/dex2oat_image_test.cc b/dex2oat/dex2oat_image_test.cc
index b62dd832fc..34ca3e4d84 100644
--- a/dex2oat/dex2oat_image_test.cc
+++ b/dex2oat/dex2oat_image_test.cc
@@ -246,6 +246,28 @@ TEST_F(Dex2oatImageTest, TestModesAndFilters) {
classes.Close();
std::cout << "Dirty image object sizes " << image_classes_sizes << std::endl;
}
+ // Test multiple dirty image objects.
+ {
+ std::array<ScratchFile, 2> files;
+ int idx = 0;
+ VisitDexes(
+ libcore_dexes_array,
+ VoidFunctor(),
+ [&](TypeReference ref) {
+ WriteLine(files[idx].GetFile(), ref.dex_file->PrettyType(ref.TypeIndex()));
+ idx = (idx + 1) % files.size();
+ },
+ /*method_frequency=*/1u,
+ /*class_frequency=*/1u);
+ ImageSizes image_classes_sizes =
+ CompileImageAndGetSizes(dex_files,
+ {"--dirty-image-objects=" + files[0].GetFilename(),
+ "--dirty-image-objects=" + files[1].GetFilename()});
+ for (ScratchFile& file : files) {
+ file.Close();
+ }
+ std::cout << "Dirty image object sizes " << image_classes_sizes << std::endl;
+ }
}
TEST_F(Dex2oatImageTest, TestExtension) {
diff --git a/dex2oat/dex2oat_options.cc b/dex2oat/dex2oat_options.cc
index 34a72f084e..635961e5f8 100644
--- a/dex2oat/dex2oat_options.cc
+++ b/dex2oat/dex2oat_options.cc
@@ -194,12 +194,12 @@ static void AddImageMappings(Builder& builder) {
"images.")
.IntoKey(M::MultiImage)
.Define("--dirty-image-objects=_")
- .WithType<std::string>()
+ .WithType<std::vector<std::string>>().AppendValues()
.WithHelp("list of known dirty objects in the image. The image writer will group them"
" together")
.IntoKey(M::DirtyImageObjects)
.Define("--dirty-image-objects-fd=_")
- .WithType<int>()
+ .WithType<std::vector<int>>().AppendValues()
.WithHelp("Specify a file descriptor for reading the list of known dirty objects in\n"
"the image. The image writer will group them together")
.IntoKey(M::DirtyImageObjectsFd)
diff --git a/dex2oat/dex2oat_options.def b/dex2oat/dex2oat_options.def
index 7cf9d023b7..10c4eccfa0 100644
--- a/dex2oat/dex2oat_options.def
+++ b/dex2oat/dex2oat_options.def
@@ -89,8 +89,8 @@ DEX2OAT_OPTIONS_KEY (std::string, InvocationFile)
DEX2OAT_OPTIONS_KEY (std::string, ClassLoaderContext)
DEX2OAT_OPTIONS_KEY (std::string, ClassLoaderContextFds)
DEX2OAT_OPTIONS_KEY (std::string, StoredClassLoaderContext)
-DEX2OAT_OPTIONS_KEY (std::string, DirtyImageObjects)
-DEX2OAT_OPTIONS_KEY (int, DirtyImageObjectsFd)
+DEX2OAT_OPTIONS_KEY (std::vector<std::string>, DirtyImageObjects)
+DEX2OAT_OPTIONS_KEY (std::vector<int>, DirtyImageObjectsFd)
DEX2OAT_OPTIONS_KEY (std::string, UpdatableBcpPackagesFile)
DEX2OAT_OPTIONS_KEY (int, UpdatableBcpPackagesFd)
DEX2OAT_OPTIONS_KEY (std::vector<std::string>, RuntimeOptions)
diff --git a/odrefresh/odrefresh.cc b/odrefresh/odrefresh.cc
index 6a09a88a4e..733e22f99d 100644
--- a/odrefresh/odrefresh.cc
+++ b/odrefresh/odrefresh.cc
@@ -1872,22 +1872,24 @@ OnDeviceRefresh::RunDex2oatForBootClasspath(const std::string& staging_dir,
args.Add(StringPrintf("--base=0x%08x", ART_BASE_ADDRESS));
- std::string dirty_image_objects_file(GetAndroidRoot() + "/etc/dirty-image-objects");
- std::unique_ptr<File> file(OS::OpenFileForReading(dirty_image_objects_file.c_str()));
- if (file != nullptr) {
- args.Add("--dirty-image-objects-fd=%d", file->Fd());
- readonly_files_raii.push_back(std::move(file));
- } else if (errno == ENOENT) {
- LOG(WARNING) << ART_FORMAT("Missing dirty objects file '{}'", dirty_image_objects_file);
- } else {
- return CompilationResult::Error(OdrMetrics::Status::kIoError,
- ART_FORMAT("Failed to open dirty objects file '{}': {}",
- dirty_image_objects_file,
- strerror(errno)));
+ for (const std::string& prefix : {GetAndroidRoot(), GetArtRoot()}) {
+ std::string dirty_image_objects_file = prefix + "/etc/dirty-image-objects";
+ std::unique_ptr<File> file(OS::OpenFileForReading(dirty_image_objects_file.c_str()));
+ if (file != nullptr) {
+ args.Add("--dirty-image-objects-fd=%d", file->Fd());
+ readonly_files_raii.push_back(std::move(file));
+ } else if (errno == ENOENT) {
+ LOG(WARNING) << ART_FORMAT("Missing dirty objects file '{}'", dirty_image_objects_file);
+ } else {
+ return CompilationResult::Error(OdrMetrics::Status::kIoError,
+ ART_FORMAT("Failed to open dirty objects file '{}': {}",
+ dirty_image_objects_file,
+ strerror(errno)));
+ }
}
std::string preloaded_classes_file(GetAndroidRoot() + "/etc/preloaded-classes");
- file.reset(OS::OpenFileForReading(preloaded_classes_file.c_str()));
+ std::unique_ptr<File> file(OS::OpenFileForReading(preloaded_classes_file.c_str()));
if (file != nullptr) {
args.Add("--preloaded-classes-fds=%d", file->Fd());
readonly_files_raii.push_back(std::move(file));
diff --git a/odrefresh/odrefresh_test.cc b/odrefresh/odrefresh_test.cc
index 424b606ff8..f44c3211c3 100644
--- a/odrefresh/odrefresh_test.cc
+++ b/odrefresh/odrefresh_test.cc
@@ -177,9 +177,9 @@ class OdRefreshTest : public CommonArtTest {
CreateEmptyFile(dirty_image_objects_file_);
preloaded_classes_file_ = system_etc_dir + "/preloaded-classes";
CreateEmptyFile(preloaded_classes_file_);
- std::string art_etc_dir = android_art_root_path + "/etc";
- ASSERT_TRUE(EnsureDirectoryExists(art_etc_dir));
- art_profile_ = art_etc_dir + "/boot-image.prof";
+ art_etc_dir_ = android_art_root_path + "/etc";
+ ASSERT_TRUE(EnsureDirectoryExists(art_etc_dir_));
+ art_profile_ = art_etc_dir_ + "/boot-image.prof";
CreateEmptyFile(art_profile_);
framework_dir_ = android_root_path + "/framework";
@@ -267,6 +267,7 @@ class OdRefreshTest : public CommonArtTest {
std::string services_foo_jar_;
std::string services_bar_jar_;
std::string dalvik_cache_dir_;
+ std::string art_etc_dir_;
std::string framework_dir_;
std::string framework_profile_;
std::string art_profile_;
@@ -1011,5 +1012,55 @@ TEST_F(OdRefreshTest, OnlyBootImages) {
ExitCode::kCompilationSuccess);
}
+TEST_F(OdRefreshTest, DirtyImageObjects) {
+ // Primary.
+ EXPECT_CALL(*mock_exec_utils_,
+ DoExecAndReturnCode(AllOf(
+ Contains(Flag("--dirty-image-objects-fd=", FdOf(dirty_image_objects_file_))),
+ Contains(Flag("--dex-file=", core_oj_jar_)))))
+ .WillOnce(Return(0));
+
+ // Mainline extension.
+ EXPECT_CALL(*mock_exec_utils_,
+ DoExecAndReturnCode(AllOf(Contains(Flag("--dex-file=", conscrypt_jar_)))))
+ .WillOnce(Return(0));
+
+ EXPECT_EQ(odrefresh_->Compile(
+ *metrics_,
+ CompilationOptions{
+ .boot_images_to_generate_for_isas{
+ {InstructionSet::kX86_64,
+ {.primary_boot_image = true, .boot_image_mainline_extension = true}}},
+ }),
+ ExitCode::kCompilationSuccess);
+}
+
+TEST_F(OdRefreshTest, DirtyImageObjectsMultipleFiles) {
+ std::string art_dirty_image_objects = art_etc_dir_ + "/dirty-image-objects";
+ auto file = ScopedCreateEmptyFile(art_dirty_image_objects);
+
+ // Primary.
+ EXPECT_CALL(*mock_exec_utils_,
+ DoExecAndReturnCode(AllOf(
+ Contains(Flag("--dirty-image-objects-fd=", FdOf(dirty_image_objects_file_))),
+ Contains(Flag("--dirty-image-objects-fd=", FdOf(art_dirty_image_objects))),
+ Contains(Flag("--dex-file=", core_oj_jar_)))))
+ .WillOnce(Return(0));
+
+ // Mainline extension.
+ EXPECT_CALL(*mock_exec_utils_,
+ DoExecAndReturnCode(AllOf(Contains(Flag("--dex-file=", conscrypt_jar_)))))
+ .WillOnce(Return(0));
+
+ EXPECT_EQ(odrefresh_->Compile(
+ *metrics_,
+ CompilationOptions{
+ .boot_images_to_generate_for_isas{
+ {InstructionSet::kX86_64,
+ {.primary_boot_image = true, .boot_image_mainline_extension = true}}},
+ }),
+ ExitCode::kCompilationSuccess);
+}
+
} // namespace odrefresh
} // namespace art