diff options
author | 2024-06-18 16:59:52 +0000 | |
---|---|---|
committer | 2024-07-03 14:55:10 +0000 | |
commit | bfb7f772d13b28d4cde86692b92547dddd06c5d2 (patch) | |
tree | 41a9e1e3009e7400b88b2dec86f2427cbe2bbf71 | |
parent | c1d49fdab3302ed1222f7b2ee1e3e3ccd7df892d (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.cc | 45 | ||||
-rw-r--r-- | dex2oat/dex2oat_image_test.cc | 22 | ||||
-rw-r--r-- | dex2oat/dex2oat_options.cc | 4 | ||||
-rw-r--r-- | dex2oat/dex2oat_options.def | 4 | ||||
-rw-r--r-- | odrefresh/odrefresh.cc | 28 | ||||
-rw-r--r-- | odrefresh/odrefresh_test.cc | 57 |
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 |