Snap for 8073075 from 4a75f4a7162b32edc194077dec85e027b9e457ef to tm-release
Change-Id: I96978f1b2c1b5a3a08a64295f6cfdb4cac2d09d4
diff --git a/artd/binder/private/com/android/art/DexoptBcpExtArgs.aidl b/artd/binder/private/com/android/art/DexoptBcpExtArgs.aidl
index 43fd922..8253ead 100644
--- a/artd/binder/private/com/android/art/DexoptBcpExtArgs.aidl
+++ b/artd/binder/private/com/android/art/DexoptBcpExtArgs.aidl
@@ -44,7 +44,7 @@
// manually.
String[] bootClasspaths;
int[] bootClasspathFds;
- int profileFd = -1;
+ int[] profileFds;
int dirtyImageObjectsFd = -1;
// Output file descriptors
int oatFd = -1;
diff --git a/artd/binder/private/com/android/art/DexoptSystemServerArgs.aidl b/artd/binder/private/com/android/art/DexoptSystemServerArgs.aidl
index bfb94e1..54aa867 100644
--- a/artd/binder/private/com/android/art/DexoptSystemServerArgs.aidl
+++ b/artd/binder/private/com/android/art/DexoptSystemServerArgs.aidl
@@ -60,7 +60,7 @@
String dexPath;
String oatLocation;
String[] classloaderContext;
- boolean isBootImageOnSystem;
+ String bootImage;
boolean classloaderContextAsParent;
// SECURITY: The server may accept the request to produce code for the specified architecture,
diff --git a/artd/libdexopt.cc b/artd/libdexopt.cc
index 853f950..b6982c1 100644
--- a/artd/libdexopt.cc
+++ b/artd/libdexopt.cc
@@ -43,11 +43,6 @@
using android::base::Error;
using android::base::Result;
-std::string GetBootImage() {
- // Typically "/apex/com.android.art/javalib/boot.art".
- return art::GetArtRoot() + "/javalib/boot.art";
-}
-
std::string GetEnvironmentVariableOrDie(const char* name) {
const char* value = getenv(name);
LOG_ALWAYS_FATAL_IF(value == nullptr, "%s is not defined.", name);
@@ -206,8 +201,10 @@
cmdline.emplace_back("--instruction-set=" + ToInstructionSetString(args.isa));
- if (args.profileFd >= 0) {
- cmdline.emplace_back(android::base::StringPrintf("--profile-file-fd=%d", args.profileFd));
+ if (!args.profileFds.empty()) {
+ for (int fd : args.profileFds) {
+ cmdline.emplace_back(android::base::StringPrintf("--profile-file-fd=%d", fd));
+ }
cmdline.emplace_back("--compiler-filter=speed-profile");
} else {
cmdline.emplace_back("--compiler-filter=speed");
@@ -216,8 +213,7 @@
// Compile as a single image for fewer files and slightly less memory overhead.
cmdline.emplace_back("--single-image");
- // Set boot-image and expectation of compiling boot classpath extensions.
- cmdline.emplace_back("--boot-image=" + GetBootImage());
+ cmdline.emplace_back(android::base::StringPrintf("--base=0x%08x", ART_BASE_ADDRESS));
if (args.dirtyImageObjectsFd >= 0) {
cmdline.emplace_back(android::base::StringPrintf("--dirty-image-objects-fd=%d",
@@ -321,23 +317,7 @@
android::base::Join(args.classloaderFds, ':'));
}
- // Derive boot image
- // b/197176583
- // If the boot extension artifacts are not on /data, then boot extensions are not re-compiled
- // and the artifacts must exist on /system.
- std::vector<std::string> jar_paths = android::base::Split(GetDex2oatBootClasspath(), ":");
- auto iter = std::find_if_not(jar_paths.begin(), jar_paths.end(), &LocationIsOnArtModule);
- if (iter == jar_paths.end()) {
- return Error() << "Missing BCP extension compatible JAR";
- }
- const std::string& first_boot_extension_compatible_jars = *iter;
- // TODO(197176583): Support compiling against BCP extension in /system.
- const std::string extension_image = GetBootImagePath(args.isBootImageOnSystem,
- first_boot_extension_compatible_jars);
- if (extension_image.empty()) {
- return Error() << "Can't identify the first boot extension compatible jar";
- }
- cmdline.emplace_back("--boot-image=" + GetBootImage() + ":" + extension_image);
+ cmdline.emplace_back("--boot-image=" + args.bootImage);
AddDex2OatConcurrencyArguments(cmdline, args.threads, args.cpuSet);
diff --git a/artd/libdexopt_test.cc b/artd/libdexopt_test.cc
index e73c5d6..3cc340b 100644
--- a/artd/libdexopt_test.cc
+++ b/artd/libdexopt_test.cc
@@ -58,7 +58,7 @@
default_bcp_ext_args_.bootClasspaths = android::base::Split(
GetEnvironmentVariableOrDie("DEX2OATBOOTCLASSPATH"), ":"); // from art_artd_tests.xml
default_bcp_ext_args_.bootClasspathFds = {21, 22};
- default_bcp_ext_args_.profileFd = 30;
+ default_bcp_ext_args_.profileFds = {30, 31};
default_bcp_ext_args_.dirtyImageObjectsFd = 31;
default_bcp_ext_args_.imageFd = 90;
default_bcp_ext_args_.vdexFd = 91;
@@ -90,7 +90,7 @@
default_system_server_args_.compilerFilter = CompilerFilter::SPEED_PROFILE;
default_system_server_args_.cpuSet = {0, 1};
default_system_server_args_.threads = 42;
- default_system_server_args_.isBootImageOnSystem = true;
+ default_system_server_args_.bootImage = "/path/to/boot.art";
ASSERT_EQ(default_system_server_args_.bootClasspaths.size(),
default_system_server_args_.bootClasspathFds.size());
}
@@ -134,32 +134,35 @@
{
std::vector<std::string> cmdline = Dex2oatArgsFromBcpExtensionArgs(default_bcp_ext_args_);
- EXPECT_THAT(cmdline, AllOf(
- Contains("--dex-fd=10"),
- Contains("--dex-fd=11"),
- Contains("--dex-file=/path/to/foo.jar"),
- Contains("--dex-file=/path/to/bar.jar"),
- Contains(HasSubstr("-Xbootclasspath:")),
- Contains("-Xbootclasspathfds:21:22"),
+ EXPECT_THAT(cmdline,
+ AllOf(Contains("--dex-fd=10"),
+ Contains("--dex-fd=11"),
+ Contains("--dex-file=/path/to/foo.jar"),
+ Contains("--dex-file=/path/to/bar.jar"),
+ Contains(HasSubstr("-Xbootclasspath:")),
+ Contains("-Xbootclasspathfds:21:22"),
- Contains("--profile-file-fd=30"),
- Contains("--compiler-filter=speed-profile"),
+ Contains("--profile-file-fd=30"),
+ Contains("--profile-file-fd=31"),
+ Contains("--compiler-filter=speed-profile"),
- Contains("--image-fd=90"),
- Contains("--output-vdex-fd=91"),
- Contains("--oat-fd=92"),
- Contains("--oat-location=/oat/location/bar.odex"),
+ Contains("--image-fd=90"),
+ Contains("--output-vdex-fd=91"),
+ Contains("--oat-fd=92"),
+ Contains("--oat-location=/oat/location/bar.odex"),
- Contains("--dirty-image-objects-fd=31"),
- Contains("--instruction-set=x86_64"),
- Contains("--cpu-set=0,1"),
- Contains("-j42")));
+ Contains("--dirty-image-objects-fd=31"),
+ Contains("--instruction-set=x86_64"),
+ Contains("--cpu-set=0,1"),
+ Contains("-j42"),
+
+ Contains(HasSubstr("--base="))));
}
// No profile
{
auto args = default_bcp_ext_args_;
- args.profileFd = -1;
+ args.profileFds = {};
std::vector<std::string> cmdline = Dex2oatArgsFromBcpExtensionArgs(args);
EXPECT_THAT(cmdline, AllOf(
@@ -224,29 +227,31 @@
{
std::vector<std::string> cmdline = Dex2oatArgsFromSystemServerArgs(default_system_server_args_);
- EXPECT_THAT(cmdline, AllOf(
- Contains("--dex-fd=10"),
- Contains("--dex-file=/path/to/foo.jar"),
- Contains(HasSubstr("-Xbootclasspath:")),
- Contains("-Xbootclasspathfds:21:22:23"),
- Contains("-Xbootclasspathimagefds:-1:31:-1"),
- Contains("-Xbootclasspathvdexfds:-1:32:-1"),
- Contains("-Xbootclasspathoatfds:-1:33:-1"),
+ EXPECT_THAT(cmdline,
+ AllOf(Contains("--dex-fd=10"),
+ Contains("--dex-file=/path/to/foo.jar"),
+ Contains(HasSubstr("-Xbootclasspath:")),
+ Contains("-Xbootclasspathfds:21:22:23"),
+ Contains("-Xbootclasspathimagefds:-1:31:-1"),
+ Contains("-Xbootclasspathvdexfds:-1:32:-1"),
+ Contains("-Xbootclasspathoatfds:-1:33:-1"),
- Contains("--profile-file-fd=11"),
- Contains("--compiler-filter=speed-profile"),
+ Contains("--profile-file-fd=11"),
+ Contains("--compiler-filter=speed-profile"),
- Contains("--app-image-fd=90"),
- Contains("--output-vdex-fd=91"),
- Contains("--oat-fd=92"),
- Contains("--oat-location=/oat/location/bar.odex"),
+ Contains("--app-image-fd=90"),
+ Contains("--output-vdex-fd=91"),
+ Contains("--oat-fd=92"),
+ Contains("--oat-location=/oat/location/bar.odex"),
- Contains("--class-loader-context-fds=40:41"),
- Contains("--class-loader-context=PCL[/cl/abc.jar:/cl/def.jar]"),
+ Contains("--class-loader-context-fds=40:41"),
+ Contains("--class-loader-context=PCL[/cl/abc.jar:/cl/def.jar]"),
- Contains("--instruction-set=x86_64"),
- Contains("--cpu-set=0,1"),
- Contains("-j42")));
+ Contains("--instruction-set=x86_64"),
+ Contains("--cpu-set=0,1"),
+ Contains("-j42"),
+
+ Contains("--boot-image=/path/to/boot.art")));
}
// Test different compiler filters
diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc
index 1002f2c..cc57f6a 100644
--- a/compiler/optimizing/code_generator_arm64.cc
+++ b/compiler/optimizing/code_generator_arm64.cc
@@ -1987,6 +1987,9 @@
if (codegen_->CanUseImplicitSuspendCheck()) {
__ Ldr(kImplicitSuspendCheckRegister, MemOperand(kImplicitSuspendCheckRegister));
codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
+ if (successor != nullptr) {
+ __ B(codegen_->GetLabelOf(successor));
+ }
return;
}
@@ -3583,9 +3586,7 @@
if (info != nullptr && info->IsBackEdge(*block) && info->HasSuspendCheck()) {
codegen_->MaybeIncrementHotness(/* is_frame_entry= */ false);
GenerateSuspendCheck(info->GetSuspendCheck(), successor);
- if (!codegen_->CanUseImplicitSuspendCheck()) {
- return; // `GenerateSuspendCheck()` emitted the jump.
- }
+ return; // `GenerateSuspendCheck()` emitted the jump.
}
if (block->IsEntryBlock() && (previous != nullptr) && previous->IsSuspendCheck()) {
GenerateSuspendCheck(previous->AsSuspendCheck(), nullptr);
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index 123165d..b8271d8 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -833,8 +833,7 @@
// Set the compilation target's implicit checks options.
switch (compiler_options_->GetInstructionSet()) {
case InstructionSet::kArm64:
- // TODO: Investigate implicit suspend check regressions. Bug: 209235730, 213121241.
- compiler_options_->implicit_suspend_checks_ = false;
+ compiler_options_->implicit_suspend_checks_ = true;
FALLTHROUGH_INTENDED;
case InstructionSet::kArm:
case InstructionSet::kThumb2:
@@ -1237,7 +1236,6 @@
input_vdex_file_ = VdexFile::Open(input_vdex_,
/* writable */ false,
/* low_4gb */ false,
- DoEagerUnquickeningOfVdex(),
&error_msg);
}
@@ -1246,8 +1244,8 @@
? ReplaceFileExtension(oat_filename, "vdex")
: output_vdex_;
if (vdex_filename == input_vdex_ && output_vdex_.empty()) {
- update_input_vdex_ = true;
- std::unique_ptr<File> vdex_file(OS::OpenFileReadWrite(vdex_filename.c_str()));
+ use_existing_vdex_ = true;
+ std::unique_ptr<File> vdex_file(OS::OpenFileForReading(vdex_filename.c_str()));
vdex_files_.push_back(std::move(vdex_file));
} else {
std::unique_ptr<File> vdex_file(OS::CreateEmptyFile(vdex_filename.c_str()));
@@ -1289,7 +1287,6 @@
"vdex",
/* writable */ false,
/* low_4gb */ false,
- DoEagerUnquickeningOfVdex(),
&error_msg);
// If there's any problem with the passed vdex, just warn and proceed
// without it.
@@ -1301,15 +1298,20 @@
DCHECK_NE(output_vdex_fd_, -1);
std::string vdex_location = ReplaceFileExtension(oat_location_, "vdex");
- std::unique_ptr<File> vdex_file(new File(
- DupCloexec(output_vdex_fd_), vdex_location, /* check_usage */ true));
+ if (input_vdex_file_ != nullptr && output_vdex_fd_ == input_vdex_fd_) {
+ use_existing_vdex_ = true;
+ }
+
+ std::unique_ptr<File> vdex_file(new File(DupCloexec(output_vdex_fd_),
+ vdex_location,
+ /* check_usage= */ true,
+ /* read_only_mode= */ use_existing_vdex_));
if (!vdex_file->IsOpened()) {
PLOG(ERROR) << "Failed to create vdex file: " << vdex_location;
return false;
}
- if (input_vdex_file_ != nullptr && output_vdex_fd_ == input_vdex_fd_) {
- update_input_vdex_ = true;
- } else {
+
+ if (!use_existing_vdex_) {
if (vdex_file->SetLength(0) != 0) {
PLOG(ERROR) << "Truncating vdex file " << vdex_location << " failed.";
vdex_file->Erase();
@@ -1321,26 +1323,6 @@
oat_filenames_.push_back(oat_location_);
}
- // If we're updating in place a vdex file, be defensive and put an invalid vdex magic in case
- // dex2oat gets killed.
- // Note: we're only invalidating the magic data in the file, as dex2oat needs the rest of
- // the information to remain valid.
- if (update_input_vdex_) {
- File* vdex_file = vdex_files_.back().get();
- if (!vdex_file->PwriteFully(&VdexFile::VdexFileHeader::kVdexInvalidMagic,
- arraysize(VdexFile::VdexFileHeader::kVdexInvalidMagic),
- /*offset=*/ 0u)) {
- PLOG(ERROR) << "Failed to invalidate vdex header. File: " << vdex_file->GetPath();
- return false;
- }
-
- if (vdex_file->Flush() != 0) {
- PLOG(ERROR) << "Failed to flush stream after invalidating header of vdex file."
- << " File: " << vdex_file->GetPath();
- return false;
- }
- }
-
if (dm_fd_ != -1 || !dm_file_location_.empty()) {
std::string error_msg;
if (dm_fd_ != -1) {
@@ -1389,9 +1371,12 @@
void EraseOutputFiles() {
for (auto& files : { &vdex_files_, &oat_files_ }) {
for (size_t i = 0; i < files->size(); ++i) {
- if ((*files)[i].get() != nullptr) {
- (*files)[i]->Erase();
- (*files)[i].reset();
+ auto& file = (*files)[i];
+ if (file != nullptr) {
+ if (!file->ReadOnlyMode()) {
+ file->Erase();
+ }
+ file.reset();
}
}
}
@@ -1455,7 +1440,7 @@
if (!oat_writers_[i]->WriteAndOpenDexFiles(
vdex_files_[i].get(),
verify,
- update_input_vdex_,
+ use_existing_vdex_,
copy_dex_files_,
&opened_dex_files_map,
&opened_dex_files)) {
@@ -1695,21 +1680,16 @@
}
}
- // Ensure opened dex files are writable for dex-to-dex transformations.
- for (MemMap& map : opened_dex_files_maps_) {
- if (!map.Protect(PROT_READ | PROT_WRITE)) {
- PLOG(ERROR) << "Failed to make .dex files writeable.";
- return dex2oat::ReturnCode::kOther;
- }
- }
-
// Setup VerifierDeps for compilation and report if we fail to parse the data.
- if (!DoEagerUnquickeningOfVdex() && input_vdex_file_ != nullptr) {
+ // When we do profile guided optimizations, the compiler currently needs to run
+ // full verification.
+ if (!DoProfileGuidedOptimizations() && input_vdex_file_ != nullptr) {
std::unique_ptr<verifier::VerifierDeps> verifier_deps(
new verifier::VerifierDeps(dex_files, /*output_only=*/ false));
if (!verifier_deps->ParseStoredData(dex_files, input_vdex_file_->GetVerifierDepsData())) {
return dex2oat::ReturnCode::kOther;
}
+ // We can do fast verification.
callbacks_->SetVerifierDeps(verifier_deps.release());
} else {
// Create the main VerifierDeps, here instead of in the compiler since we want to aggregate
@@ -1792,7 +1772,7 @@
// This means extract, no-vdex verify, and quicken, will use the individual compilation
// mode (to reduce RAM used by the compiler).
return compile_individually_ &&
- (!IsImage() && !update_input_vdex_ &&
+ (!IsImage() && !use_existing_vdex_ &&
compiler_options_->dex_files_for_oat_file_.size() > 1 &&
!CompilerFilter::IsAotCompilationEnabled(compiler_options_->GetCompilerFilter()));
}
@@ -2069,7 +2049,7 @@
oat_writer->Initialize(driver_.get(), image_writer_.get(), dex_files);
}
- {
+ if (!use_existing_vdex_) {
TimingLogger::ScopedTiming t2("dex2oat Write VDEX", timings_);
DCHECK(IsBootImage() || IsBootImageExtension() || oat_files_.size() == 1u);
verifier::VerifierDeps* verifier_deps = callbacks_->GetVerifierDeps();
@@ -2235,7 +2215,7 @@
}
bool FlushOutputFile(std::unique_ptr<File>* file) {
- if (file->get() != nullptr) {
+ if ((file->get() != nullptr) && !file->get()->ReadOnlyMode()) {
if (file->get()->Flush() != 0) {
PLOG(ERROR) << "Failed to flush output file: " << file->get()->GetPath();
return false;
@@ -2245,7 +2225,7 @@
}
bool FlushCloseOutputFile(File* file) {
- if (file != nullptr) {
+ if ((file != nullptr) && !file->ReadOnlyMode()) {
if (file->FlushCloseOrErase() != 0) {
PLOG(ERROR) << "Failed to flush and close output file: " << file->GetPath();
return false;
@@ -2325,16 +2305,6 @@
return DoProfileGuidedOptimizations();
}
- bool MayInvalidateVdexMetadata() const {
- // DexLayout can invalidate the vdex metadata if changing the class def order is enabled, so
- // we need to unquicken the vdex file eagerly, before passing it to dexlayout.
- return DoDexLayoutOptimizations();
- }
-
- bool DoEagerUnquickeningOfVdex() const {
- return MayInvalidateVdexMetadata() && dm_file_ == nullptr;
- }
-
bool LoadProfile() {
DCHECK(HasProfileInput());
profile_load_attempted_ = true;
@@ -2948,7 +2918,7 @@
std::string classpath_dir_;
// Whether the given input vdex is also the output.
- bool update_input_vdex_ = false;
+ bool use_existing_vdex_ = false;
// By default, copy the dex to the vdex file only if dex files are
// compressed in APK.
diff --git a/dex2oat/dex2oat_test.cc b/dex2oat/dex2oat_test.cc
index 557675d..b340c80 100644
--- a/dex2oat/dex2oat_test.cc
+++ b/dex2oat/dex2oat_test.cc
@@ -1812,7 +1812,6 @@
std::unique_ptr<VdexFile> vdex(VdexFile::Open(vdex_location.c_str(),
/*writable=*/ false,
/*low_4gb=*/ false,
- /*unquicken=*/ false,
&error_msg));
ASSERT_TRUE(vdex != nullptr);
EXPECT_FALSE(vdex->HasDexSection()) << output_;
diff --git a/dex2oat/dex2oat_vdex_test.cc b/dex2oat/dex2oat_vdex_test.cc
index 1f486e6..895e9c2 100644
--- a/dex2oat/dex2oat_vdex_test.cc
+++ b/dex2oat/dex2oat_vdex_test.cc
@@ -73,7 +73,6 @@
std::unique_ptr<VdexFile> vdex(VdexFile::Open(vdex_location.c_str(),
/*writable=*/ false,
/*low_4gb=*/ false,
- /*unquicken=*/ false,
&error_msg_));
// Check the vdex doesn't have dex.
if (vdex->HasDexSection()) {
diff --git a/dex2oat/driver/compiler_driver.cc b/dex2oat/driver/compiler_driver.cc
index 0f4638d..caf8753 100644
--- a/dex2oat/driver/compiler_driver.cc
+++ b/dex2oat/driver/compiler_driver.cc
@@ -487,7 +487,8 @@
}
} else if ((access_flags & kAccAbstract) != 0) {
// Abstract methods don't have code.
- } else if (annotations::MethodIsNeverCompile(dex_file, dex_file.GetClassDef(class_def_idx),
+ } else if (annotations::MethodIsNeverCompile(dex_file,
+ dex_file.GetClassDef(class_def_idx),
method_idx)) {
// Method is annotated with @NeverCompile and should not be compiled.
} else {
diff --git a/dex2oat/linker/oat_writer.cc b/dex2oat/linker/oat_writer.cc
index 5ac2bbf..70260bc 100644
--- a/dex2oat/linker/oat_writer.cc
+++ b/dex2oat/linker/oat_writer.cc
@@ -683,21 +683,22 @@
bool OatWriter::WriteAndOpenDexFiles(
File* vdex_file,
bool verify,
- bool update_input_vdex,
+ bool use_existing_vdex,
CopyOption copy_dex_files,
/*out*/ std::vector<MemMap>* opened_dex_files_map,
/*out*/ std::vector<std::unique_ptr<const DexFile>>* opened_dex_files) {
CHECK(write_state_ == WriteState::kAddingDexFileSources);
+ // Reserve space for Vdex header, sections, and checksums.
size_vdex_header_ = sizeof(VdexFile::VdexFileHeader) +
VdexSection::kNumberOfSections * sizeof(VdexFile::VdexSectionHeader);
- // Reserve space for Vdex header, sections, and checksums.
- vdex_size_ = size_vdex_header_ + oat_dex_files_.size() * sizeof(VdexFile::VdexChecksum);
+ size_vdex_checksums_ = oat_dex_files_.size() * sizeof(VdexFile::VdexChecksum);
+ vdex_size_ = size_vdex_header_ + size_vdex_checksums_;
// Write DEX files into VDEX, mmap and open them.
std::vector<MemMap> dex_files_map;
std::vector<std::unique_ptr<const DexFile>> dex_files;
- if (!WriteDexFiles(vdex_file, update_input_vdex, copy_dex_files, &dex_files_map) ||
+ if (!WriteDexFiles(vdex_file, use_existing_vdex, copy_dex_files, &dex_files_map) ||
!OpenDexFiles(vdex_file, verify, &dex_files_map, &dex_files)) {
return false;
}
@@ -3103,7 +3104,7 @@
}
bool OatWriter::WriteDexFiles(File* file,
- bool update_input_vdex,
+ bool use_existing_vdex,
CopyOption copy_dex_files,
/*out*/ std::vector<MemMap>* opened_dex_files_map) {
TimingLogger::ScopedTiming split("Write Dex files", timings_);
@@ -3136,8 +3137,8 @@
if (profile_compilation_info_ != nullptr ||
compact_dex_level_ != CompactDexLevel::kCompactDexLevelNone) {
for (OatDexFile& oat_dex_file : oat_dex_files_) {
- // update_input_vdex disables compact dex and layout.
- CHECK(!update_input_vdex)
+ // use_existing_vdex should not be used with compact dex and layout.
+ CHECK(!use_existing_vdex)
<< "We should never update the input vdex when doing dexlayout or compact dex";
if (!LayoutDexFile(&oat_dex_file)) {
return false;
@@ -3202,7 +3203,7 @@
// Extend the file and include the full page at the end as we need to write
// additional data there and do not want to mmap that page twice.
size_t page_aligned_size = RoundUp(vdex_size_with_dex_files, kPageSize);
- if (!update_input_vdex) {
+ if (!use_existing_vdex) {
if (file->SetLength(page_aligned_size) != 0) {
PLOG(ERROR) << "Failed to resize vdex file " << file->GetPath();
return false;
@@ -3212,7 +3213,7 @@
std::string error_msg;
MemMap dex_files_map = MemMap::MapFile(
page_aligned_size,
- PROT_READ | PROT_WRITE,
+ use_existing_vdex ? PROT_READ : PROT_READ | PROT_WRITE,
MAP_SHARED,
file->Fd(),
/*start=*/ 0u,
@@ -3233,7 +3234,7 @@
vdex_size_ = RoundUp(vdex_size_, 4u);
size_dex_file_alignment_ += vdex_size_ - old_vdex_size;
// Write the actual dex file.
- if (!WriteDexFile(file, &oat_dex_file, update_input_vdex)) {
+ if (!WriteDexFile(file, &oat_dex_file, use_existing_vdex)) {
return false;
}
}
@@ -3241,27 +3242,25 @@
// Write shared dex file data section and fix up the dex file headers.
if (shared_data_size != 0u) {
DCHECK_EQ(RoundUp(vdex_size_, 4u), vdex_dex_shared_data_offset_);
- if (!update_input_vdex) {
- memset(vdex_begin_ + vdex_size_, 0, vdex_dex_shared_data_offset_ - vdex_size_);
- }
+ DCHECK(!use_existing_vdex);
+ memset(vdex_begin_ + vdex_size_, 0, vdex_dex_shared_data_offset_ - vdex_size_);
size_dex_file_alignment_ += vdex_dex_shared_data_offset_ - vdex_size_;
vdex_size_ = vdex_dex_shared_data_offset_;
if (dex_container_ != nullptr) {
- CHECK(!update_input_vdex) << "Update input vdex should have empty dex container";
+ CHECK(!use_existing_vdex) << "Use existing vdex should have empty dex container";
CHECK(compact_dex_level_ != CompactDexLevel::kCompactDexLevelNone);
DexContainer::Section* const section = dex_container_->GetDataSection();
DCHECK_EQ(shared_data_size, section->Size());
memcpy(vdex_begin_ + vdex_size_, section->Begin(), shared_data_size);
section->Clear();
dex_container_.reset();
- } else if (!update_input_vdex) {
- // If we are not updating the input vdex, write out the shared data section.
+ } else {
memcpy(vdex_begin_ + vdex_size_, raw_dex_file_shared_data_begin, shared_data_size);
}
vdex_size_ += shared_data_size;
size_dex_file_ += shared_data_size;
- if (!update_input_vdex) {
+ if (!use_existing_vdex) {
// Fix up the dex headers to have correct offsets to the data section.
for (OatDexFile& oat_dex_file : oat_dex_files_) {
DexFile::Header* header =
@@ -3283,6 +3282,14 @@
vdex_dex_shared_data_offset_ = vdex_size_;
}
+ if (use_existing_vdex) {
+ // If we re-use an existing vdex, artificially set the verifier deps size,
+ // so the compiler has a correct computation of the vdex size.
+ size_t actual_size = file->GetLength();
+ size_verifier_deps_ = actual_size - vdex_size_;
+ vdex_size_ = actual_size;
+ }
+
return true;
}
@@ -3297,22 +3304,22 @@
bool OatWriter::WriteDexFile(File* file,
OatDexFile* oat_dex_file,
- bool update_input_vdex) {
+ bool use_existing_vdex) {
DCHECK_EQ(vdex_size_, oat_dex_file->dex_file_offset_);
if (oat_dex_file->source_.IsZipEntry()) {
- DCHECK(!update_input_vdex);
+ DCHECK(!use_existing_vdex);
if (!WriteDexFile(file, oat_dex_file, oat_dex_file->source_.GetZipEntry())) {
return false;
}
} else if (oat_dex_file->source_.IsRawFile()) {
- DCHECK(!update_input_vdex);
+ DCHECK(!use_existing_vdex);
if (!WriteDexFile(file, oat_dex_file, oat_dex_file->source_.GetRawFile())) {
return false;
}
} else {
DCHECK(oat_dex_file->source_.IsRawData());
const uint8_t* raw_data = oat_dex_file->source_.GetRawData();
- if (!WriteDexFile(oat_dex_file, raw_data, update_input_vdex)) {
+ if (!WriteDexFile(oat_dex_file, raw_data, use_existing_vdex)) {
return false;
}
}
@@ -3447,14 +3454,14 @@
bool OatWriter::WriteDexFile(OatDexFile* oat_dex_file,
const uint8_t* dex_file,
- bool update_input_vdex) {
+ bool use_existing_vdex) {
// Note: The raw data has already been checked to contain the header
// and all the data that the header specifies as the file size.
DCHECK(dex_file != nullptr);
DCHECK(ValidateDexFileHeader(dex_file, oat_dex_file->GetLocation()));
DCHECK_EQ(oat_dex_file->dex_file_size_, AsUnalignedDexFileHeader(dex_file)->file_size_);
- if (update_input_vdex) {
+ if (use_existing_vdex) {
// The vdex already contains the dex code, no need to write it again.
} else {
uint8_t* raw_output = vdex_begin_ + oat_dex_file->dex_file_offset_;
@@ -3763,7 +3770,6 @@
for (size_t i = 0, size = oat_dex_files_.size(); i != size; ++i) {
OatDexFile* oat_dex_file = &oat_dex_files_[i];
checksums_data[i] = oat_dex_file->dex_file_location_checksum_;
- size_vdex_checksums_ += sizeof(VdexFile::VdexChecksum);
}
// Write sections.
diff --git a/dex2oat/linker/oat_writer.h b/dex2oat/linker/oat_writer.h
index 87174eb..ad14d60 100644
--- a/dex2oat/linker/oat_writer.h
+++ b/dex2oat/linker/oat_writer.h
@@ -157,11 +157,11 @@
// Write raw dex files to the vdex file, mmap the file and open the dex files from it.
// The `verify` setting dictates whether the dex file verifier should check the dex files.
// This is generally the case, and should only be false for tests.
- // If `update_input_vdex` is true, then this method won't actually write the dex files,
+ // If `use_existing_vdex` is true, then this method won't actually write the dex files,
// and the compiler will just re-use the existing vdex file.
bool WriteAndOpenDexFiles(File* vdex_file,
bool verify,
- bool update_input_vdex,
+ bool use_existing_vdex,
CopyOption copy_dex_files,
/*out*/ std::vector<MemMap>* opened_dex_files_map,
/*out*/ std::vector<std::unique_ptr<const DexFile>>* opened_dex_files);
@@ -276,12 +276,12 @@
// If `update_input_vdex` is true, then this method won't actually write the dex files,
// and the compiler will just re-use the existing vdex file.
bool WriteDexFiles(File* file,
- bool update_input_vdex,
+ bool use_existing_vdex,
CopyOption copy_dex_files,
/*out*/ std::vector<MemMap>* opened_dex_files_map);
bool WriteDexFile(File* file,
OatDexFile* oat_dex_file,
- bool update_input_vdex);
+ bool use_existing_vdex);
bool LayoutDexFile(OatDexFile* oat_dex_file);
bool WriteDexFile(File* file,
OatDexFile* oat_dex_file,
@@ -291,7 +291,7 @@
File* dex_file);
bool WriteDexFile(OatDexFile* oat_dex_file,
const uint8_t* dex_file,
- bool update_input_vdex);
+ bool use_existing_vdex);
bool OpenDexFiles(File* file,
bool verify,
/*inout*/ std::vector<MemMap>* opened_dex_files_map,
diff --git a/dexlayout/dexdiag.cc b/dexlayout/dexdiag.cc
index a9ea27d..9aa0353 100644
--- a/dexlayout/dexdiag.cc
+++ b/dexlayout/dexdiag.cc
@@ -330,7 +330,6 @@
std::unique_ptr<VdexFile> vdex(VdexFile::Open(vdex_name,
/*writable=*/ false,
/*low_4gb=*/ false,
- /*unquicken= */ false,
&error_msg /*out*/));
if (vdex == nullptr) {
std::cerr << "Could not open vdex file "
diff --git a/dexlayout/dexlayout.h b/dexlayout/dexlayout.h
index 9bb7b8b..bdc7863 100644
--- a/dexlayout/dexlayout.h
+++ b/dexlayout/dexlayout.h
@@ -99,7 +99,10 @@
// Setting this to false disables class def layout entirely, which is stronger than strictly
// necessary to ensure the partial order w.r.t. class derivation. TODO: Re-enable (b/68317550).
+ // This should never be set for a device build, as changing class defs ids
+ // conflict with profiles and verification passed by Play.
static constexpr bool kChangeClassDefOrder = false;
+ static_assert(!(kIsTargetBuild && kChangeClassDefOrder), "Never set class reordering on target");
DexLayout(Options& options,
ProfileCompilationInfo* info,
diff --git a/libartbase/Android.bp b/libartbase/Android.bp
index 06c8cfc..1f034e6 100644
--- a/libartbase/Android.bp
+++ b/libartbase/Android.bp
@@ -236,13 +236,11 @@
static: {
whole_static_libs: [
"libc++fs",
- "libprocinfo",
],
},
shared: {
static_libs: [
"libc++fs",
- "libprocinfo",
],
},
}
diff --git a/libartbase/base/common_art_test.cc b/libartbase/base/common_art_test.cc
index 20bc87c..593ea25 100644
--- a/libartbase/base/common_art_test.cc
+++ b/libartbase/base/common_art_test.cc
@@ -50,7 +50,6 @@
#include "dex/primitive.h"
#include "gtest/gtest.h"
#include "nativehelper/scoped_local_ref.h"
-#include "procinfo/process.h"
namespace art {
@@ -680,12 +679,16 @@
std::vector<pid_t> GetPidByName(const std::string& process_name) {
std::vector<pid_t> results;
for (pid_t pid : android::base::AllPids{}) {
- android::procinfo::ProcessInfo process_info;
- std::string error;
- if (!android::procinfo::GetProcessInfo(pid, &process_info, &error)) {
+ std::string cmdline;
+ if (!android::base::ReadFileToString(StringPrintf("/proc/%d/cmdline", pid), &cmdline)) {
continue;
}
- if (process_info.name == process_name) {
+ // Take the first argument.
+ size_t pos = cmdline.find('\0');
+ if (pos != std::string::npos) {
+ cmdline.resize(pos);
+ }
+ if (cmdline == process_name) {
results.push_back(pid);
}
}
diff --git a/libartbase/base/common_art_test.h b/libartbase/base/common_art_test.h
index a33c632..6124ed9 100644
--- a/libartbase/base/common_art_test.h
+++ b/libartbase/base/common_art_test.h
@@ -287,8 +287,8 @@
template <typename Param>
using CommonArtTestWithParam = CommonArtTestBase<testing::TestWithParam<Param>>;
-// Returns a list of PIDs of the processes whose process name (the name of the binary without path)
-// fully matches the given name.
+// Returns a list of PIDs of the processes whose process name (the first commandline argument) fully
+// matches the given name.
std::vector<pid_t> GetPidByName(const std::string& process_name);
#define TEST_DISABLED_FOR_TARGET() \
diff --git a/libartbase/base/file_utils.cc b/libartbase/base/file_utils.cc
index bc08f30..07402a3 100644
--- a/libartbase/base/file_utils.cc
+++ b/libartbase/base/file_utils.cc
@@ -283,65 +283,33 @@
return GetAndroidDir(kArtApexDataEnvVar, kArtApexDataDefaultPath, /*must_exist=*/false);
}
-static std::string GetFirstBootClasspathExtensionJar(const std::string& android_root) {
- DCHECK(kIsTargetBuild);
-
- // This method finds the first non-APEX DEX file in the boot class path as defined by the
- // DEX2OATBOOTCLASSPATH environment variable. This corresponds to the first boot classpath
- // extension (see IMAGE SECTION documentation in image.h). When on-device signing is used the
- // boot class extensions are compiled together as a single image with a name derived from the
- // first extension. This first boot classpath extension is usually
- // '/system/framework/framework.jar'.
- //
- // DEX2OATBOOTCLASSPATH is generated at build time by in the init.environ.rc.in:
- // ${ANDROID_BUILD_TOP}/system/core/rootdir/Android.mk
- // and initialized on Android by init in init.environ.rc:
- // ${ANDROID_BUILD_TOP}/system/core/rootdir/init.environ.rc.in.
- // It is used by installd too.
- const char* bcp = getenv("DEX2OATBOOTCLASSPATH");
- const std::string kDefaultBcpExtensionJar = android_root + "/framework/framework.jar";
- if (bcp != nullptr) {
- for (std::string_view component : SplitString(bcp, ':')) {
- if (component.empty()) {
- continue;
- }
- if (!LocationIsOnApex(component)) {
- return std::string{component};
- }
- }
- }
- return kDefaultBcpExtensionJar;
-}
-
std::string GetDefaultBootImageLocation(const std::string& android_root,
bool deny_art_apex_data_files) {
constexpr static const char* kJavalibBootArt = "javalib/boot.art";
constexpr static const char* kEtcBootImageProf = "etc/boot-image.prof";
- // Boot image consists of two parts:
- // - the primary boot image in the ART APEX (contains the Core Libraries)
- // - the boot image extensions (contains framework libraries) on the system partition, or
- // in the ART APEX data directory, if an update for the ART module has been been installed.
+ // If an update for the ART module has been been installed, a single boot image for the entire
+ // bootclasspath is in the ART APEX data directory.
if (kIsTargetBuild && !deny_art_apex_data_files) {
- // If the ART APEX has been updated, the compiled boot image extension will be in the ART APEX
- // data directory (assuming there is space and we trust the artifacts there). Otherwise, for a factory installed ART APEX it is
- // under $ANDROID_ROOT/framework/.
- const std::string first_extension_jar{GetFirstBootClasspathExtensionJar(android_root)};
- const std::string boot_extension_image = GetApexDataBootImage(first_extension_jar);
- const std::string boot_extension_filename =
- GetSystemImageFilename(boot_extension_image.c_str(), kRuntimeISA);
- if (OS::FileExists(boot_extension_filename.c_str(), /*check_file_type=*/true)) {
- return StringPrintf("%s/%s:%s!%s/%s",
+ const std::string boot_image =
+ GetApexDataDalvikCacheDirectory(InstructionSet::kNone) + "/boot.art";
+ const std::string boot_image_filename = GetSystemImageFilename(boot_image.c_str(), kRuntimeISA);
+ if (OS::FileExists(boot_image_filename.c_str(), /*check_file_type=*/true)) {
+ return StringPrintf("%s!%s/%s!%s/%s",
+ boot_image.c_str(),
kAndroidArtApexDefaultPath,
- kJavalibBootArt,
- boot_extension_image.c_str(),
+ kEtcBootImageProf,
android_root.c_str(),
kEtcBootImageProf);
} else if (errno == EACCES) {
// Additional warning for potential SELinux misconfiguration.
- PLOG(ERROR) << "Default boot image check failed, could not stat: " << boot_extension_image;
+ PLOG(ERROR) << "Default boot image check failed, could not stat: " << boot_image_filename;
}
}
+ // Boot image consists of two parts:
+ // - the primary boot image in the ART APEX (contains the Core Libraries)
+ // - the boot image extensions (contains framework libraries) on the system partition
+ // TODO(b/211973309): Update this once the primary boot image is moved.
return StringPrintf("%s/%s:%s/framework/boot-framework.art!%s/%s",
kAndroidArtApexDefaultPath,
kJavalibBootArt,
@@ -358,18 +326,6 @@
return GetDefaultBootImageLocation(android_root, /*deny_art_apex_data_files=*/false);
}
-std::string GetBootImagePath(bool on_system, const std::string& jar_path) {
- if (on_system) {
- const std::string jar_name = android::base::Basename(jar_path);
- const std::string image_name = ReplaceFileExtension(jar_name, "art");
- // Typically "/system/framework/boot-framework.art".
- return StringPrintf("%s/framework/boot-%s", GetAndroidRoot().c_str(), image_name.c_str());
- } else {
- // Typically "/data/misc/apexdata/com.android.art/dalvik-cache/boot-framework.art".
- return GetApexDataBootImage(jar_path);
- }
-}
-
static /*constinit*/ std::string_view dalvik_cache_sub_dir = "dalvik-cache";
void OverrideDalvikCacheSubDirectory(std::string sub_dir) {
diff --git a/libartbase/base/file_utils.h b/libartbase/base/file_utils.h
index 709ac12..97abc73 100644
--- a/libartbase/base/file_utils.h
+++ b/libartbase/base/file_utils.h
@@ -77,9 +77,6 @@
std::string GetDefaultBootImageLocation(const std::string& android_root,
bool deny_art_apex_data_files);
-// Returns the boot image path of the provided jar, on /system or /data.
-std::string GetBootImagePath(bool on_system, const std::string& jar_path);
-
// Allows the name to be used for the dalvik cache directory (normally "dalvik-cache") to be
// overridden with a new value.
void OverrideDalvikCacheSubDirectory(std::string sub_dir);
diff --git a/odrefresh/odr_artifacts.h b/odrefresh/odr_artifacts.h
index 66d76f0..30932e2 100644
--- a/odrefresh/odr_artifacts.h
+++ b/odrefresh/odr_artifacts.h
@@ -28,7 +28,7 @@
// A grouping of odrefresh generated artifacts.
class OdrArtifacts {
public:
- static OdrArtifacts ForBootImageExtension(const std::string& image_path) {
+ static OdrArtifacts ForBootImage(const std::string& image_path) {
return OdrArtifacts(image_path, "oat");
}
diff --git a/odrefresh/odr_artifacts_test.cc b/odrefresh/odr_artifacts_test.cc
index 76f2c28..b47f2a7 100644
--- a/odrefresh/odr_artifacts_test.cc
+++ b/odrefresh/odr_artifacts_test.cc
@@ -27,7 +27,7 @@
static constexpr const char* kOdrefreshArtifactDirectory = "/test/dir";
-TEST(OdrArtifactsTest, ForBootImageExtension) {
+TEST(OdrArtifactsTest, ForBootImage) {
ScopedUnsetEnvironmentVariable no_env("ART_APEX_DATA");
setenv("ART_APEX_DATA", kOdrefreshArtifactDirectory, /* overwrite */ 1);
@@ -37,7 +37,7 @@
const std::string image_filename =
GetSystemImageFilename(image_location.c_str(), InstructionSet::kArm64);
- const auto artifacts = OdrArtifacts::ForBootImageExtension(image_filename);
+ const auto artifacts = OdrArtifacts::ForBootImage(image_filename);
CHECK_EQ(std::string(kOdrefreshArtifactDirectory) + "/dalvik-cache/arm64/boot-framework.art",
artifacts.ImagePath());
CHECK_EQ(std::string(kOdrefreshArtifactDirectory) + "/dalvik-cache/arm64/boot-framework.oat",
diff --git a/odrefresh/odr_config.h b/odrefresh/odr_config.h
index 9a8b6ba..7b89a83 100644
--- a/odrefresh/odr_config.h
+++ b/odrefresh/odr_config.h
@@ -71,7 +71,7 @@
time_t max_execution_seconds_ = kMaximumExecutionSeconds;
time_t max_child_process_seconds_ = kMaxChildProcessSeconds;
std::string standalone_system_server_jars_;
- bool compilation_os_mode_;
+ bool compilation_os_mode_ = false;
// Staging directory for artifacts. The directory must exist and will be automatically removed
// after compilation. If empty, use the default directory.
@@ -87,7 +87,7 @@
const std::string& GetApexInfoListFile() const { return apex_info_list_file_; }
- std::vector<InstructionSet> GetBootExtensionIsas() const {
+ std::vector<InstructionSet> GetBootClasspathIsas() const {
const auto [isa32, isa64] = GetPotentialInstructionSets();
switch (zygote_kind_) {
case ZygoteKind::kZygote32:
diff --git a/odrefresh/odrefresh.cc b/odrefresh/odrefresh.cc
index d3cffc6..857e8ba 100644
--- a/odrefresh/odrefresh.cc
+++ b/odrefresh/odrefresh.cc
@@ -112,6 +112,8 @@
constexpr mode_t kFileMode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
+constexpr const char* kFirstBootImageBasename = "boot.art";
+
void EraseFiles(const std::vector<std::unique_ptr<File>>& files) {
for (auto& file : files) {
file->Erase(/*unlink=*/true);
@@ -208,7 +210,7 @@
}
// Returns a rewritten path based on ANDROID_ROOT if the path starts with "/system/".
-std::string AndroidRootRewrite(const std::string &path) {
+std::string AndroidRootRewrite(const std::string& path) {
if (StartsWith(path, "/system/")) {
return Concatenate({GetAndroidRoot(), path.substr(7)});
} else {
@@ -414,20 +416,30 @@
return true;
}
+std::string GetBootImageComponentBasename(const std::string& jar_path, bool is_first_jar) {
+ if (is_first_jar) {
+ return kFirstBootImageBasename;
+ }
+ const std::string jar_name = android::base::Basename(jar_path);
+ return "boot-" + ReplaceFileExtension(jar_name, "art");
+}
+
void PrepareCompiledBootClasspathFdsIfAny(
/*inout*/ DexoptSystemServerArgs& dexopt_args,
/*inout*/ std::vector<std::unique_ptr<File>>& output_files,
const std::vector<std::string>& bcp_jars,
const InstructionSet isa,
- bool on_system) {
+ const std::string& artifact_dir) {
std::vector<int> bcp_image_fds;
std::vector<int> bcp_oat_fds;
std::vector<int> bcp_vdex_fds;
std::vector<std::unique_ptr<File>> opened_files;
bool added_any = false;
- for (const std::string& jar : bcp_jars) {
- std::string image_path = GetBootImagePath(on_system, jar);
- image_path = image_path.empty() ? "" : GetSystemImageFilename(image_path.c_str(), isa);
+ for (size_t i = 0; i < bcp_jars.size(); i++) {
+ const std::string& jar = bcp_jars[i];
+ std::string image_path =
+ artifact_dir + "/" + GetBootImageComponentBasename(jar, /*is_first_jar=*/i == 0);
+ image_path = GetSystemImageFilename(image_path.c_str(), isa);
std::unique_ptr<File> image_file(OS::OpenFileForReading(image_path.c_str()));
if (image_file && image_file->IsValid()) {
bcp_image_fds.push_back(image_file->Fd());
@@ -527,6 +539,10 @@
}
}
+std::string GetArtBootImageDir() { return GetArtRoot() + "/javalib"; }
+
+std::string GetSystemBootImageDir() { return GetAndroidRoot() + "/framework"; }
+
} // namespace
OnDeviceRefresh::OnDeviceRefresh(const OdrConfig& config)
@@ -545,12 +561,9 @@
exec_utils_{std::move(exec_utils)},
odr_dexopt_{std::move(odr_dexopt)} {
for (const std::string& jar : android::base::Split(config_.GetDex2oatBootClasspath(), ":")) {
- // Boot class path extensions are those not in the ART APEX. Updatable APEXes should not
- // have DEX files in the DEX2OATBOOTCLASSPATH. At the time of writing i18n is a non-updatable
- // APEX and so does appear in the DEX2OATBOOTCLASSPATH.
- if (!LocationIsOnArtModule(jar)) {
- boot_extension_compilable_jars_.emplace_back(jar);
- }
+ // Updatable APEXes should not have DEX files in the DEX2OATBOOTCLASSPATH. At the time of
+ // writing i18n is a non-updatable APEX and so does appear in the DEX2OATBOOTCLASSPATH.
+ boot_classpath_compilable_jars_.emplace_back(jar);
}
all_systemserver_jars_ = android::base::Split(config_.GetSystemServerClasspath(), ":");
@@ -566,9 +579,7 @@
}
}
-time_t OnDeviceRefresh::GetExecutionTimeUsed() const {
- return time(nullptr) - start_time_;
-}
+time_t OnDeviceRefresh::GetExecutionTimeUsed() const { return time(nullptr) - start_time_; }
time_t OnDeviceRefresh::GetExecutionTimeRemaining() const {
return std::max(static_cast<time_t>(0),
@@ -589,8 +600,8 @@
// We are only interested in active APEXes that contain compilable JARs.
std::unordered_set<std::string_view> relevant_apexes;
relevant_apexes.reserve(info_list->getApexInfo().size());
- for (const std::vector<std::string>* jar_list : { &boot_extension_compilable_jars_,
- &all_systemserver_jars_, &boot_classpath_jars_}) {
+ for (const std::vector<std::string>* jar_list :
+ {&boot_classpath_compilable_jars_, &all_systemserver_jars_, &boot_classpath_jars_}) {
for (auto& jar : *jar_list) {
std::string_view apex = ApexNameFromLocation(jar);
if (!apex.empty()) {
@@ -606,8 +617,9 @@
std::copy_if(info_list->getApexInfo().begin(),
info_list->getApexInfo().end(),
std::back_inserter(filtered_info_list),
- [&](const apex::ApexInfo& info) { return info.getIsActive()
- && relevant_apexes.count(info.getModuleName()) != 0; });
+ [&](const apex::ApexInfo& info) {
+ return info.getIsActive() && relevant_apexes.count(info.getModuleName()) != 0;
+ });
return filtered_info_list;
}
@@ -652,15 +664,15 @@
}
std::optional<std::vector<art_apex::Component>> bcp_compilable_components =
- GenerateBootExtensionCompilableComponents();
+ GenerateBootClasspathCompilableComponents();
if (!bcp_compilable_components.has_value()) {
- return Errorf("No boot classpath extension compilable components.");
+ return Errorf("No boot classpath compilable components.");
}
std::optional<std::vector<art_apex::SystemServerComponent>> system_server_components =
GenerateSystemServerComponents();
if (!system_server_components.has_value()) {
- return Errorf("No system_server extension components.");
+ return Errorf("No system_server components.");
}
std::ofstream out(cache_info_filename_.c_str());
@@ -697,9 +709,9 @@
return GenerateComponents(boot_classpath_jars_);
}
-std::vector<art_apex::Component> OnDeviceRefresh::GenerateBootExtensionCompilableComponents()
+std::vector<art_apex::Component> OnDeviceRefresh::GenerateBootClasspathCompilableComponents()
const {
- return GenerateComponents(boot_extension_compilable_jars_);
+ return GenerateComponents(boot_classpath_compilable_jars_);
}
std::vector<art_apex::SystemServerComponent> OnDeviceRefresh::GenerateSystemServerComponents()
@@ -712,16 +724,37 @@
});
}
-std::string OnDeviceRefresh::GetBootImageExtensionImage(bool on_system) const {
- CHECK(!boot_extension_compilable_jars_.empty());
- const std::string leading_jar = boot_extension_compilable_jars_[0];
- return GetBootImagePath(on_system, leading_jar);
+std::string OnDeviceRefresh::GetBootImage(bool on_system) const {
+ if (on_system) {
+ // Typically "/apex/com.android.art/javalib/boot.art".
+ // TODO(b/211973309): Update this once the primary boot image is moved.
+ return GetArtBootImageDir() + "/" + kFirstBootImageBasename;
+ } else {
+ // Typically "/data/misc/apexdata/com.android.art/dalvik-cache/boot.art".
+ return config_.GetArtifactDirectory() + "/" + kFirstBootImageBasename;
+ }
}
-std::string OnDeviceRefresh::GetBootImageExtensionImagePath(bool on_system,
- const InstructionSet isa) const {
- // Typically "/data/misc/apexdata/com.android.art/dalvik-cache/<isa>/boot-framework.art".
- return GetSystemImageFilename(GetBootImageExtensionImage(on_system).c_str(), isa);
+std::string OnDeviceRefresh::GetBootImagePath(bool on_system, const InstructionSet isa) const {
+ // Typically "/data/misc/apexdata/com.android.art/dalvik-cache/<isa>/boot.art".
+ return GetSystemImageFilename(GetBootImage(on_system).c_str(), isa);
+}
+
+std::string OnDeviceRefresh::GetSystemBootImageExtension() const {
+ std::string art_root = GetArtRoot() + "/";
+ // Find the first boot extension jar.
+ auto it = std::find_if_not(
+ boot_classpath_compilable_jars_.begin(),
+ boot_classpath_compilable_jars_.end(),
+ [&](const std::string& jar) { return android::base::StartsWith(jar, art_root); });
+ CHECK(it != boot_classpath_compilable_jars_.end());
+ // Typically "/system/framework/boot-framework.art".
+ return GetSystemBootImageDir() + "/" + GetBootImageComponentBasename(*it, /*is_first_jar=*/false);
+}
+
+std::string OnDeviceRefresh::GetSystemBootImageExtensionPath(const InstructionSet isa) const {
+ // Typically "/system/framework/<isa>/boot-framework.art".
+ return GetSystemImageFilename(GetSystemBootImageExtension().c_str(), isa);
}
std::string OnDeviceRefresh::GetSystemServerImagePath(bool on_system,
@@ -752,14 +785,27 @@
return RemoveDirectory(config_.GetArtifactDirectory());
}
-WARN_UNUSED bool OnDeviceRefresh::BootExtensionArtifactsExist(
+WARN_UNUSED bool OnDeviceRefresh::BootClasspathArtifactsExist(
bool on_system,
const InstructionSet isa,
/*out*/ std::string* error_msg,
/*out*/ std::vector<std::string>* checked_artifacts) const {
- const std::string apexdata_image_location = GetBootImageExtensionImagePath(on_system, isa);
- const OdrArtifacts artifacts = OdrArtifacts::ForBootImageExtension(apexdata_image_location);
- return ArtifactsExist(artifacts, /*check_art_file=*/true, error_msg, checked_artifacts);
+ std::string path = GetBootImagePath(on_system, isa);
+ OdrArtifacts artifacts = OdrArtifacts::ForBootImage(path);
+ if (!ArtifactsExist(artifacts, /*check_art_file=*/true, error_msg, checked_artifacts)) {
+ return false;
+ }
+ // There is a split between the primary boot image and the extension on /system, so they need to
+ // be checked separately. This does not apply to the boot image on /data.
+ if (on_system) {
+ std::string extension_path = GetSystemBootImageExtensionPath(isa);
+ OdrArtifacts extension_artifacts = OdrArtifacts::ForBootImage(extension_path);
+ if (!ArtifactsExist(
+ extension_artifacts, /*check_art_file=*/true, error_msg, checked_artifacts)) {
+ return false;
+ }
+ }
+ return true;
}
WARN_UNUSED bool OnDeviceRefresh::SystemServerArtifactsExist(
@@ -781,7 +827,7 @@
return jars_missing_artifacts->empty();
}
-WARN_UNUSED bool OnDeviceRefresh::CheckBootExtensionArtifactsAreUpToDate(
+WARN_UNUSED bool OnDeviceRefresh::CheckBootClasspathArtifactsAreUpToDate(
OdrMetrics& metrics,
const InstructionSet isa,
const apex::ApexInfo& art_apex_info,
@@ -792,11 +838,11 @@
// ART is not updated, so we can use the artifacts on /system. Check if they exist.
std::string error_msg;
- if (BootExtensionArtifactsExist(/*on_system=*/true, isa, &error_msg)) {
+ if (BootClasspathArtifactsExist(/*on_system=*/true, isa, &error_msg)) {
return true;
}
- LOG(INFO) << "Incomplete boot extension artifacts on /system. " << error_msg;
+ LOG(INFO) << "Incomplete boot classpath artifacts on /system. " << error_msg;
LOG(INFO) << "Checking cache.";
}
@@ -857,7 +903,7 @@
// The boot class components may change unexpectedly, for example an OTA could update
// framework.jar.
const std::vector<art_apex::Component> expected_bcp_compilable_components =
- GenerateBootExtensionCompilableComponents();
+ GenerateBootClasspathCompilableComponents();
if (expected_bcp_compilable_components.size() != 0 &&
(!cache_info->hasDex2oatBootClasspath() ||
!cache_info->getFirstDex2oatBootClasspath()->hasComponent())) {
@@ -878,8 +924,8 @@
// Cache info looks good, check all compilation artifacts exist.
std::string error_msg;
- if (!BootExtensionArtifactsExist(/*on_system=*/false, isa, &error_msg, checked_artifacts)) {
- LOG(INFO) << "Incomplete boot extension artifacts. " << error_msg;
+ if (!BootClasspathArtifactsExist(/*on_system=*/false, isa, &error_msg, checked_artifacts)) {
+ LOG(INFO) << "Incomplete boot classpath artifacts. " << error_msg;
metrics.SetTrigger(OdrMetrics::Trigger::kMissingArtifacts);
return false;
}
@@ -1165,7 +1211,7 @@
// Clean-up helper used to simplify clean-ups and handling failures there.
auto cleanup_and_compile_all = [&, this]() {
- compilation_options->compile_boot_extensions_for_isas = config_.GetBootExtensionIsas();
+ compilation_options->compile_boot_classpath_for_isas = config_.GetBootClasspathIsas();
compilation_options->system_server_jars_to_compile = AllSystemServerJars();
return RemoveArtifactsDirectory() ? ExitCode::kCompilationRequired : ExitCode::kCleanupFailed;
};
@@ -1215,11 +1261,11 @@
InstructionSet system_server_isa = config_.GetSystemServerIsa();
std::vector<std::string> checked_artifacts;
- for (const InstructionSet isa : config_.GetBootExtensionIsas()) {
- if (!CheckBootExtensionArtifactsAreUpToDate(
+ for (const InstructionSet isa : config_.GetBootClasspathIsas()) {
+ if (!CheckBootClasspathArtifactsAreUpToDate(
metrics, isa, art_apex_info.value(), cache_info, &checked_artifacts)) {
- compilation_options->compile_boot_extensions_for_isas.push_back(isa);
- // system_server artifacts are invalid without valid boot extension artifacts.
+ compilation_options->compile_boot_classpath_for_isas.push_back(isa);
+ // system_server artifacts are invalid without valid boot classpath artifacts.
if (isa == system_server_isa) {
compilation_options->system_server_jars_to_compile = AllSystemServerJars();
}
@@ -1234,7 +1280,7 @@
&checked_artifacts);
}
- bool compilation_required = (!compilation_options->compile_boot_extensions_for_isas.empty() ||
+ bool compilation_required = (!compilation_options->compile_boot_classpath_for_isas.empty() ||
!compilation_options->system_server_jars_to_compile.empty());
// If partial compilation is disabled, we should compile everything regardless of what's in
@@ -1269,7 +1315,7 @@
return compilation_required ? ExitCode::kCompilationRequired : ExitCode::kOkay;
}
-WARN_UNUSED bool OnDeviceRefresh::CompileBootExtensionArtifacts(
+WARN_UNUSED bool OnDeviceRefresh::CompileBootClasspathArtifacts(
const InstructionSet isa,
const std::string& staging_dir,
OdrMetrics& metrics,
@@ -1281,10 +1327,17 @@
dexopt_args.isa = InstructionSetToAidlIsa(isa);
std::vector<std::unique_ptr<File>> readonly_files_raii;
- const std::string boot_profile_file(GetAndroidRoot() + "/etc/boot-image.prof");
+ dexopt_args.profileFds.resize(2);
+ const std::string art_boot_profile_file = GetArtRoot() + "/etc/boot-image.prof";
if (!PrepareDex2OatProfileIfExists(
- &dexopt_args.profileFd, &readonly_files_raii, boot_profile_file)) {
- LOG(ERROR) << "Missing expected profile for boot extension: " << boot_profile_file;
+ &dexopt_args.profileFds[0], &readonly_files_raii, art_boot_profile_file)) {
+ LOG(ERROR) << "Missing expected ART boot profile: " << art_boot_profile_file;
+ return false;
+ }
+ const std::string framework_boot_profile_file = GetAndroidRoot() + "/etc/boot-image.prof";
+ if (!PrepareDex2OatProfileIfExists(
+ &dexopt_args.profileFds[1], &readonly_files_raii, framework_boot_profile_file)) {
+ LOG(ERROR) << "Missing expected framework boot profile: " << framework_boot_profile_file;
return false;
}
@@ -1297,8 +1350,8 @@
LOG(WARNING) << "Missing dirty objects file : " << QuotePath(dirty_image_objects_file);
}
- // Add boot extensions to compile.
- for (const std::string& component : boot_extension_compilable_jars_) {
+ // Add boot classpath jars to compile.
+ for (const std::string& component : boot_classpath_compilable_jars_) {
std::string actual_path = AndroidRootRewrite(component);
std::unique_ptr<File> file(OS::OpenFileForReading(actual_path.c_str()));
dexopt_args.dexPaths.emplace_back(component);
@@ -1312,10 +1365,8 @@
return false;
}
- const std::string image_location = GetBootImageExtensionImagePath(/*on_system=*/false, isa);
- const OdrArtifacts artifacts = OdrArtifacts::ForBootImageExtension(image_location);
- CHECK_EQ(GetApexDataOatFilename(boot_extension_compilable_jars_.front().c_str(), isa),
- artifacts.OatPath());
+ const std::string image_location = GetBootImagePath(/*on_system=*/false, isa);
+ const OdrArtifacts artifacts = OdrArtifacts::ForBootImage(image_location);
dexopt_args.oatLocation = artifacts.OatPath();
const std::pair<const std::string, int*> location_kind_pairs[] = {
@@ -1356,7 +1407,7 @@
}
const time_t timeout = GetSubprocessTimeout();
- LOG(INFO) << "Compiling boot extensions (" << isa << "): " << dexopt_args.toString()
+ LOG(INFO) << "Compiling boot classpath (" << isa << "): " << dexopt_args.toString()
<< " [timeout " << timeout << "s]";
if (config_.GetDryRun()) {
LOG(INFO) << "Compilation skipped (dry-run).";
@@ -1364,6 +1415,9 @@
}
bool timed_out = false;
+ // NOTE: The method `DexoptBcpExtension` actually compiles the entire boot classpath. We don't
+ // rename this method because it will eventually go away.
+ // TODO(b/211977683): Call dex2oat directly.
int dex2oat_exit_code =
odr_dexopt_->DexoptBcpExtension(dexopt_args, timeout, &timed_out, error_msg);
@@ -1471,13 +1525,19 @@
return false;
}
std::string unused_error_msg;
- // If the boot extension artifacts are not on /data, then boot extensions are not re-compiled
+ // If the boot classpath artifacts are not on /data, then the boot classpath are not re-compiled
// and the artifacts must exist on /system.
bool boot_image_on_system =
- !BootExtensionArtifactsExist(/*on_system=*/false, isa, &unused_error_msg);
+ !BootClasspathArtifactsExist(/*on_system=*/false, isa, &unused_error_msg);
PrepareCompiledBootClasspathFdsIfAny(
- dexopt_args, readonly_files_raii, bcp_jars, isa, boot_image_on_system);
- dexopt_args.isBootImageOnSystem = boot_image_on_system;
+ dexopt_args,
+ readonly_files_raii,
+ bcp_jars,
+ isa,
+ boot_image_on_system ? GetSystemBootImageDir() : config_.GetArtifactDirectory());
+ dexopt_args.bootImage = boot_image_on_system ? GetBootImage(/*on_system=*/true) + ":" +
+ GetSystemBootImageExtension() :
+ GetBootImage(/*on_system=*/false);
dexopt_args.classloaderContext = classloader_context;
if (!classloader_context.empty()) {
@@ -1575,16 +1635,16 @@
uint32_t dex2oat_invocation_count = 0;
uint32_t total_dex2oat_invocation_count =
- compilation_options.compile_boot_extensions_for_isas.size() +
+ compilation_options.compile_boot_classpath_for_isas.size() +
compilation_options.system_server_jars_to_compile.size();
ReportNextBootAnimationProgress(dex2oat_invocation_count, total_dex2oat_invocation_count);
auto advance_animation_progress = [&]() {
ReportNextBootAnimationProgress(++dex2oat_invocation_count, total_dex2oat_invocation_count);
};
- const auto& bcp_instruction_sets = config_.GetBootExtensionIsas();
+ const auto& bcp_instruction_sets = config_.GetBootClasspathIsas();
DCHECK(!bcp_instruction_sets.empty() && bcp_instruction_sets.size() <= 2);
- for (const InstructionSet isa : compilation_options.compile_boot_extensions_for_isas) {
+ for (const InstructionSet isa : compilation_options.compile_boot_classpath_for_isas) {
auto stage = (isa == bcp_instruction_sets.front()) ? OdrMetrics::Stage::kPrimaryBootClasspath :
OdrMetrics::Stage::kSecondaryBootClasspath;
metrics.SetStage(stage);
@@ -1595,7 +1655,7 @@
return ExitCode::kCompilationFailed;
}
- if (!CompileBootExtensionArtifacts(
+ if (!CompileBootClasspathArtifacts(
isa, staging_dir, metrics, advance_animation_progress, &error_msg)) {
LOG(ERROR) << "Compilation of BCP failed: " << error_msg;
if (!config_.GetDryRun() && !RemoveDirectory(staging_dir)) {
diff --git a/odrefresh/odrefresh.h b/odrefresh/odrefresh.h
index bc6a68f..d749b2b 100644
--- a/odrefresh/odrefresh.h
+++ b/odrefresh/odrefresh.h
@@ -41,10 +41,10 @@
struct CompilationOptions {
// If true, update the cache info only and do not compile anything.
- bool update_cache_info_only;
+ bool update_cache_info_only = false;
- // If not empty, compile the bootclasspath extensions for ISAs in the list.
- std::vector<InstructionSet> compile_boot_extensions_for_isas;
+ // If not empty, compile the bootclasspath jars for ISAs in the list.
+ std::vector<InstructionSet> compile_boot_classpath_for_isas;
// If not empty, compile the system server jars in the list.
std::set<std::string> system_server_jars_to_compile;
@@ -60,8 +60,7 @@
std::unique_ptr<ExecUtils> exec_utils,
std::unique_ptr<OdrDexopt> odr_dexopt);
- // Returns the exit code, a list of ISAs that boot extensions should be compiled for, and a
- // boolean indicating whether the system server should be compiled.
+ // Returns the exit code and specifies what should be compiled in `compilation_options`.
WARN_UNUSED ExitCode
CheckArtifactsAreUpToDate(OdrMetrics& metrics,
/*out*/ CompilationOptions* compilation_options) const;
@@ -94,13 +93,23 @@
std::vector<com::android::art::Component> GenerateBootClasspathComponents() const;
- std::vector<com::android::art::Component> GenerateBootExtensionCompilableComponents() const;
+ std::vector<com::android::art::Component> GenerateBootClasspathCompilableComponents() const;
std::vector<com::android::art::SystemServerComponent> GenerateSystemServerComponents() const;
- std::string GetBootImageExtensionImage(bool on_system) const;
+ // Returns the symbolic boot image location (without ISA).
+ std::string GetBootImage(bool on_system) const;
- std::string GetBootImageExtensionImagePath(bool on_system, const InstructionSet isa) const;
+ // Returns the real boot image location (with ISA).
+ std::string GetBootImagePath(bool on_system, const InstructionSet isa) const;
+
+ // Returns the symbolic boot image extension location (without ISA). Note that this only applies
+ // to boot images on /system.
+ std::string GetSystemBootImageExtension() const;
+
+ // Returns the real boot image location extension (with ISA). Note that this only applies to boot
+ // images on /system.
+ std::string GetSystemBootImageExtensionPath(const InstructionSet isa) const;
std::string GetSystemServerImagePath(bool on_system, const std::string& jar_path) const;
@@ -113,10 +122,10 @@
// artifacts to fs-verity.
android::base::Result<void> RefreshExistingArtifacts() const;
- // Checks whether all boot extension artifacts are present. Returns true if all are present, false
+ // Checks whether all boot classpath artifacts are present. Returns true if all are present, false
// otherwise.
// If `checked_artifacts` is present, adds checked artifacts to `checked_artifacts`.
- WARN_UNUSED bool BootExtensionArtifactsExist(
+ WARN_UNUSED bool BootClasspathArtifactsExist(
bool on_system,
const InstructionSet isa,
/*out*/ std::string* error_msg,
@@ -132,10 +141,10 @@
/*out*/ std::set<std::string>* jars_missing_artifacts,
/*out*/ std::vector<std::string>* checked_artifacts = nullptr) const;
- // Checks whether all boot extension artifacts are up to date. Returns true if all are present,
+ // Checks whether all boot classpath artifacts are up to date. Returns true if all are present,
// false otherwise.
// If `checked_artifacts` is present, adds checked artifacts to `checked_artifacts`.
- WARN_UNUSED bool CheckBootExtensionArtifactsAreUpToDate(
+ WARN_UNUSED bool CheckBootClasspathArtifactsAreUpToDate(
OdrMetrics& metrics,
const InstructionSet isa,
const com::android::apex::ApexInfo& art_apex_info,
@@ -153,7 +162,7 @@
/*out*/ std::set<std::string>* jars_to_compile,
/*out*/ std::vector<std::string>* checked_artifacts) const;
- WARN_UNUSED bool CompileBootExtensionArtifacts(const InstructionSet isa,
+ WARN_UNUSED bool CompileBootClasspathArtifacts(const InstructionSet isa,
const std::string& staging_dir,
OdrMetrics& metrics,
const std::function<void()>& on_dex2oat_success,
@@ -172,8 +181,8 @@
// Path to cache information file that is used to speed up artifact checking.
const std::string cache_info_filename_;
- // List of boot extension components that should be compiled.
- std::vector<std::string> boot_extension_compilable_jars_;
+ // List of boot classpath components that should be compiled.
+ std::vector<std::string> boot_classpath_compilable_jars_;
// Set of system_server components in SYSTEMSERVERCLASSPATH that should be compiled.
std::unordered_set<std::string> systemserver_classpath_jars_;
diff --git a/odrefresh/odrefresh_main.cc b/odrefresh/odrefresh_main.cc
index 8262805..f93ee93 100644
--- a/odrefresh/odrefresh_main.cc
+++ b/odrefresh/odrefresh_main.cc
@@ -185,16 +185,14 @@
NO_RETURN void UsageHelp(const char* argv0) {
std::string name(android::base::Basename(argv0));
UsageMsg("Usage: %s [OPTION...] ACTION", name.c_str());
- UsageMsg("On-device refresh tool for boot class path extensions and system server");
+ UsageMsg("On-device refresh tool for boot classpath and system server");
UsageMsg("following an update of the ART APEX.");
UsageMsg("");
UsageMsg("Valid ACTION choices are:");
UsageMsg("");
UsageMsg("--check Check compilation artifacts are up-to-date based on metadata.");
- UsageMsg("--compile Compile boot class path extensions and system_server jars");
- UsageMsg(" when necessary.");
- UsageMsg("--force-compile Unconditionally compile the boot class path extensions and");
- UsageMsg(" system_server jars.");
+ UsageMsg("--compile Compile boot classpath and system_server jars when necessary.");
+ UsageMsg("--force-compile Unconditionally compile the bootclass path and system_server jars.");
UsageMsg("--help Display this help information.");
UsageMsg("");
UsageMsg("Available OPTIONs are:");
@@ -270,8 +268,8 @@
}
return odr.Compile(metrics,
CompilationOptions{
- .compile_boot_extensions_for_isas = config.GetBootExtensionIsas(),
- .system_server_jars_to_compile = odr.AllSystemServerJars(),
+ .compile_boot_classpath_for_isas = config.GetBootClasspathIsas(),
+ .system_server_jars_to_compile = odr.AllSystemServerJars(),
});
} else if (action == "--help") {
UsageHelp(argv[0]);
diff --git a/odrefresh/odrefresh_test.cc b/odrefresh/odrefresh_test.cc
index 7494084..370fd0d 100644
--- a/odrefresh/odrefresh_test.cc
+++ b/odrefresh/odrefresh_test.cc
@@ -159,8 +159,12 @@
std::string system_etc_dir = Concatenate({android_root_path, "/etc"});
ASSERT_TRUE(EnsureDirectoryExists(system_etc_dir));
- boot_profile_file_ = system_etc_dir + "/boot-image.prof";
- CreateEmptyFile(boot_profile_file_);
+ framework_profile_ = system_etc_dir + "/boot-image.prof";
+ CreateEmptyFile(framework_profile_);
+ std::string art_etc_dir = Concatenate({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";
framework_jar_ = framework_dir_ + "/framework.jar";
@@ -169,8 +173,8 @@
services_foo_jar_ = framework_dir_ + "/services-foo.jar";
services_bar_jar_ = framework_dir_ + "/services-bar.jar";
std::string services_jar_prof = framework_dir_ + "/services.jar.prof";
- std::string javalib_dir = android_art_root_path + "/javalib";
- std::string boot_art = javalib_dir + "/boot.art";
+ art_javalib_dir_ = android_art_root_path + "/javalib";
+ core_oj_jar_ = art_javalib_dir_ + "/core-oj.jar";
// Create placeholder files.
ASSERT_TRUE(EnsureDirectoryExists(framework_dir_ + "/x86_64"));
@@ -180,16 +184,16 @@
CreateEmptyFile(services_foo_jar_);
CreateEmptyFile(services_bar_jar_);
CreateEmptyFile(services_jar_prof);
- ASSERT_TRUE(EnsureDirectoryExists(javalib_dir));
- CreateEmptyFile(boot_art);
+ ASSERT_TRUE(EnsureDirectoryExists(art_javalib_dir_));
+ CreateEmptyFile(core_oj_jar_);
std::string apex_info_filename = Concatenate({temp_dir_path, "/apex-info-list.xml"});
WriteFakeApexInfoList(apex_info_filename);
config_.SetApexInfoListFile(apex_info_filename);
config_.SetArtBinDir(Concatenate({temp_dir_path, "/bin"}));
- config_.SetBootClasspath(framework_jar_);
- config_.SetDex2oatBootclasspath(framework_jar_);
+ config_.SetBootClasspath(Concatenate({core_oj_jar_, ":", framework_jar_}));
+ config_.SetDex2oatBootclasspath(Concatenate({core_oj_jar_, ":", framework_jar_}));
config_.SetSystemServerClasspath(Concatenate({location_provider_jar_, ":", services_jar_}));
config_.SetStandaloneSystemServerJars(Concatenate({services_foo_jar_, ":", services_bar_jar_}));
config_.SetIsa(InstructionSet::kX86_64);
@@ -230,6 +234,7 @@
std::unique_ptr<ScopedUnsetEnvironmentVariable> art_apex_data_env_;
OdrConfig config_;
std::unique_ptr<OdrMetrics> metrics_;
+ std::string core_oj_jar_;
std::string framework_jar_;
std::string location_provider_jar_;
std::string services_jar_;
@@ -237,9 +242,32 @@
std::string services_bar_jar_;
std::string dalvik_cache_dir_;
std::string framework_dir_;
- std::string boot_profile_file_;
+ std::string art_javalib_dir_;
+ std::string framework_profile_;
+ std::string art_profile_;
};
+TEST_F(OdRefreshTest, BootClasspathJars) {
+ auto [odrefresh, mock_odr_dexopt] = CreateOdRefresh();
+
+ EXPECT_CALL(*mock_odr_dexopt,
+ DoDexoptBcpExtension(AllOf(
+ Field(&DexoptBcpExtArgs::dexPaths, ElementsAre(core_oj_jar_, framework_jar_)),
+ AllOf(Field(&DexoptBcpExtArgs::dexFds,
+ ElementsAre(FdOf(core_oj_jar_), FdOf(framework_jar_))),
+ Field(&DexoptBcpExtArgs::profileFds,
+ ElementsAre(FdOf(art_profile_), FdOf(framework_profile_))),
+ Field(&DexoptBcpExtArgs::oatLocation,
+ Eq(dalvik_cache_dir_ + "/x86_64/boot.oat"))))))
+ .WillOnce(Return(0));
+
+ EXPECT_EQ(odrefresh->Compile(*metrics_,
+ CompilationOptions{
+ .compile_boot_classpath_for_isas = {InstructionSet::kX86_64},
+ }),
+ ExitCode::kCompilationSuccess);
+}
+
TEST_F(OdRefreshTest, AllSystemServerJars) {
auto [odrefresh, mock_odr_dexopt] = CreateOdRefresh();
@@ -442,7 +470,7 @@
EXPECT_EQ(
odrefresh->Compile(*metrics_,
CompilationOptions{
- .compile_boot_extensions_for_isas = {InstructionSet::kX86_64},
+ .compile_boot_classpath_for_isas = {InstructionSet::kX86_64},
.system_server_jars_to_compile = odrefresh->AllSystemServerJars(),
}),
ExitCode::kCompilationSuccess);
@@ -453,21 +481,20 @@
auto [odrefresh, mock_odr_dexopt] = CreateOdRefresh();
// Boot image is on /data.
- OdrArtifacts artifacts =
- OdrArtifacts::ForBootImageExtension(dalvik_cache_dir_ + "/x86_64/boot-framework.art");
+ OdrArtifacts artifacts = OdrArtifacts::ForBootImage(dalvik_cache_dir_ + "/x86_64/boot.art");
auto file1 = ScopedCreateEmptyFile(artifacts.ImagePath());
auto file2 = ScopedCreateEmptyFile(artifacts.VdexPath());
auto file3 = ScopedCreateEmptyFile(artifacts.OatPath());
- EXPECT_CALL(
- *mock_odr_dexopt,
- DoDexoptSystemServer(AllOf(Field(&DexoptSystemServerArgs::isBootImageOnSystem, Eq(false)),
- Field(&DexoptSystemServerArgs::bootClasspathImageFds,
- Contains(FdOf(artifacts.ImagePath()))),
- Field(&DexoptSystemServerArgs::bootClasspathVdexFds,
- Contains(FdOf(artifacts.VdexPath()))),
- Field(&DexoptSystemServerArgs::bootClasspathOatFds,
- Contains(FdOf(artifacts.OatPath()))))))
+ EXPECT_CALL(*mock_odr_dexopt,
+ DoDexoptSystemServer(AllOf(
+ Field(&DexoptSystemServerArgs::bootImage, Eq(dalvik_cache_dir_ + "/boot.art")),
+ Field(&DexoptSystemServerArgs::bootClasspathImageFds,
+ Contains(FdOf(artifacts.ImagePath()))),
+ Field(&DexoptSystemServerArgs::bootClasspathVdexFds,
+ Contains(FdOf(artifacts.VdexPath()))),
+ Field(&DexoptSystemServerArgs::bootClasspathOatFds,
+ Contains(FdOf(artifacts.OatPath()))))))
.Times(odrefresh->AllSystemServerJars().size())
.WillRepeatedly(Return(0));
EXPECT_EQ(
@@ -483,20 +510,23 @@
// Boot image is on /system.
OdrArtifacts artifacts =
- OdrArtifacts::ForBootImageExtension(framework_dir_ + "/x86_64/boot-framework.art");
+ OdrArtifacts::ForBootImage(framework_dir_ + "/x86_64/boot-framework.art");
auto file1 = ScopedCreateEmptyFile(artifacts.ImagePath());
auto file2 = ScopedCreateEmptyFile(artifacts.VdexPath());
auto file3 = ScopedCreateEmptyFile(artifacts.OatPath());
- EXPECT_CALL(
- *mock_odr_dexopt,
- DoDexoptSystemServer(AllOf(Field(&DexoptSystemServerArgs::isBootImageOnSystem, Eq(true)),
- Field(&DexoptSystemServerArgs::bootClasspathImageFds,
- Contains(FdOf(artifacts.ImagePath()))),
- Field(&DexoptSystemServerArgs::bootClasspathVdexFds,
- Contains(FdOf(artifacts.VdexPath()))),
- Field(&DexoptSystemServerArgs::bootClasspathOatFds,
- Contains(FdOf(artifacts.OatPath()))))))
+ EXPECT_CALL(*mock_odr_dexopt,
+ DoDexoptSystemServer(
+ AllOf(Field(&DexoptSystemServerArgs::bootImage,
+ Eq(android::base::StringPrintf("%s/boot.art:%s/boot-framework.art",
+ art_javalib_dir_.c_str(),
+ framework_dir_.c_str()))),
+ Field(&DexoptSystemServerArgs::bootClasspathImageFds,
+ Contains(FdOf(artifacts.ImagePath()))),
+ Field(&DexoptSystemServerArgs::bootClasspathVdexFds,
+ Contains(FdOf(artifacts.VdexPath()))),
+ Field(&DexoptSystemServerArgs::bootClasspathOatFds,
+ Contains(FdOf(artifacts.OatPath()))))))
.Times(odrefresh->AllSystemServerJars().size())
.WillRepeatedly(Return(0));
EXPECT_EQ(
diff --git a/perfetto_hprof/Android.bp b/perfetto_hprof/Android.bp
index b2c9dad..a81a4fa 100644
--- a/perfetto_hprof/Android.bp
+++ b/perfetto_hprof/Android.bp
@@ -52,7 +52,6 @@
shared_libs: [
"libbase",
"liblog",
- "libdexfile",
],
static_libs: [
"libperfetto_client_experimental",
@@ -77,6 +76,7 @@
shared_libs: [
"libart",
"libartbase",
+ "libdexfile",
],
apex_available: [
"com.android.art",
@@ -93,6 +93,7 @@
shared_libs: [
"libartd",
"libartbased",
+ "libdexfiled",
],
apex_available: [
"com.android.art.debug",
diff --git a/runtime/arch/arm/quick_entrypoints_arm.S b/runtime/arch/arm/quick_entrypoints_arm.S
index 6145d9a..a3db9f6 100644
--- a/runtime/arch/arm/quick_entrypoints_arm.S
+++ b/runtime/arch/arm/quick_entrypoints_arm.S
@@ -1286,10 +1286,11 @@
bx lr
END art_quick_test_suspend
+ .extern artImplicitSuspendFromCode
ENTRY art_quick_implicit_suspend
mov r0, rSELF
SETUP_SAVE_REFS_ONLY_FRAME r1 @ save callee saves for stack crawl
- bl artTestSuspendFromCode @ (Thread*)
+ bl artImplicitSuspendFromCode @ (Thread*)
RESTORE_SAVE_REFS_ONLY_FRAME
REFRESH_MARKING_REGISTER
bx lr
diff --git a/runtime/arch/arm64/quick_entrypoints_arm64.S b/runtime/arch/arm64/quick_entrypoints_arm64.S
index 3683fdd..7fb6ff0 100644
--- a/runtime/arch/arm64/quick_entrypoints_arm64.S
+++ b/runtime/arch/arm64/quick_entrypoints_arm64.S
@@ -1624,12 +1624,12 @@
/*
* Redirection point from implicit suspend check fault handler.
*/
- .extern artTestSuspendFromCode
+ .extern artImplicitSuspendFromCode
ENTRY art_quick_implicit_suspend
// Save callee saves for stack crawl.
SETUP_SAVE_EVERYTHING_FRAME RUNTIME_SAVE_EVERYTHING_FOR_SUSPEND_CHECK_METHOD_OFFSET
mov x0, xSELF
- bl artTestSuspendFromCode // (Thread*)
+ bl artImplicitSuspendFromCode // (Thread*)
RESTORE_SAVE_EVERYTHING_FRAME
REFRESH_MARKING_REGISTER
REFRESH_SUSPEND_CHECK_REGISTER
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 3f5b09f..d2ab81e 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -3672,8 +3672,8 @@
// Check if the native method is annotated with @FastNative or @CriticalNative.
access_flags |= annotations::GetNativeMethodAnnotationAccessFlags(
dex_file, dst->GetClassDef(), dex_method_idx);
- }
- if (annotations::MethodIsNeverCompile(dex_file, dst->GetClassDef(), dex_method_idx)) {
+ } else if ((access_flags & kAccAbstract) == 0u &&
+ annotations::MethodIsNeverCompile(dex_file, dst->GetClassDef(), dex_method_idx)) {
access_flags |= kAccCompileDontBother;
}
dst->SetAccessFlags(access_flags);
diff --git a/runtime/entrypoints/quick/quick_thread_entrypoints.cc b/runtime/entrypoints/quick/quick_thread_entrypoints.cc
index d8c1ee2..93422cf 100644
--- a/runtime/entrypoints/quick/quick_thread_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_thread_entrypoints.cc
@@ -22,11 +22,17 @@
namespace art {
extern "C" void artTestSuspendFromCode(Thread* self) REQUIRES_SHARED(Locks::mutator_lock_) {
- // Called when suspend count check value is 0 and thread->suspend_count_ != 0
+ // Called when there is a pending checkpoint or suspend request.
ScopedQuickEntrypointChecks sqec(self);
self->CheckSuspend();
}
+extern "C" void artImplicitSuspendFromCode(Thread* self) REQUIRES_SHARED(Locks::mutator_lock_) {
+ // Called when there is a pending checkpoint or suspend request.
+ ScopedQuickEntrypointChecks sqec(self);
+ self->CheckSuspend(/*implicit=*/ true);
+}
+
extern "C" void artCompileOptimized(ArtMethod* method, Thread* self)
REQUIRES_SHARED(Locks::mutator_lock_) {
ScopedQuickEntrypointChecks sqec(self);
diff --git a/runtime/jit/jit.h b/runtime/jit/jit.h
index c0c4536..fc7f071 100644
--- a/runtime/jit/jit.h
+++ b/runtime/jit/jit.h
@@ -273,6 +273,10 @@
return options_->GetThreadPoolPthreadPriority();
}
+ int GetZygoteThreadPoolPthreadPriority() const {
+ return options_->GetZygoteThreadPoolPthreadPriority();
+ }
+
uint16_t HotMethodThreshold() const {
return options_->GetOptimizeThreshold();
}
diff --git a/runtime/oat.h b/runtime/oat.h
index e44187e..36ef459 100644
--- a/runtime/oat.h
+++ b/runtime/oat.h
@@ -32,8 +32,8 @@
class PACKED(4) OatHeader {
public:
static constexpr std::array<uint8_t, 4> kOatMagic { { 'o', 'a', 't', '\n' } };
- // Last oat version changed reason: ARM64: Disable implicit suspend checks.
- static constexpr std::array<uint8_t, 4> kOatVersion { { '2', '1', '8', '\0' } };
+ // Last oat version changed reason: ARM64: Enable implicit suspend checks; madvise().
+ static constexpr std::array<uint8_t, 4> kOatVersion { { '2', '1', '9', '\0' } };
static constexpr const char* kDex2OatCmdLineKey = "dex2oat-cmdline";
static constexpr const char* kDebuggableKey = "debuggable";
diff --git a/runtime/oat_file.cc b/runtime/oat_file.cc
index 54e3712..c80feaf 100644
--- a/runtime/oat_file.cc
+++ b/runtime/oat_file.cc
@@ -190,10 +190,6 @@
}
private:
- // Returns true if we want to remove quickened opcodes before loading the VDEX file, false
- // otherwise.
- bool ShouldUnquickenVDex() const;
-
DISALLOW_COPY_AND_ASSIGN(OatFileBase);
};
@@ -280,23 +276,6 @@
return ret.release();
}
-bool OatFileBase::ShouldUnquickenVDex() const {
- // We sometimes load oat files without a runtime (eg oatdump) and don't want to do anything in
- // that case. If we are debuggable there are no -quick opcodes to unquicken. If the runtime is not
- // debuggable we don't care whether there are -quick opcodes or not so no need to do anything.
- Runtime* runtime = Runtime::Current();
- return (runtime != nullptr && runtime->IsJavaDebuggable()) &&
- // Note: This is called before `OatFileBase::Setup()` where we validate the
- // oat file contents. Check that we have at least a valid header, including
- // oat file version, to avoid parsing the key-value store for a different
- // version (out-of-date oat file) which can lead to crashes. b/179221298.
- // TODO: While this is a poor workaround and the correct solution would be
- // to postpone the unquickening check until after `OatFileBase::Setup()`,
- // we prefer to avoid larger rewrites because quickening is deprecated and
- // should be removed completely anyway. b/170086509
- (GetOatHeader().IsValid() && !IsDebuggable());
-}
-
bool OatFileBase::LoadVdex(const std::string& vdex_filename,
bool writable,
bool low_4gb,
@@ -307,7 +286,6 @@
vdex_filename,
writable,
low_4gb,
- ShouldUnquickenVDex(),
error_msg);
if (vdex_.get() == nullptr) {
*error_msg = StringPrintf("Failed to load vdex file '%s' %s",
@@ -338,7 +316,6 @@
vdex_filename,
writable,
low_4gb,
- ShouldUnquickenVDex(),
error_msg);
if (vdex_.get() == nullptr) {
*error_msg = "Failed opening vdex file.";
diff --git a/runtime/oat_file_assistant.cc b/runtime/oat_file_assistant.cc
index 414b24e..c303a7b 100644
--- a/runtime/oat_file_assistant.cc
+++ b/runtime/oat_file_assistant.cc
@@ -877,7 +877,6 @@
filename_,
/*writable=*/ false,
/*low_4gb=*/ false,
- /*unquicken=*/ false,
&error_msg);
}
}
@@ -885,7 +884,6 @@
vdex = VdexFile::Open(filename_,
/*writable=*/ false,
/*low_4gb=*/ false,
- /*unquicken=*/ false,
&error_msg);
}
if (vdex == nullptr) {
diff --git a/runtime/oat_file_manager.cc b/runtime/oat_file_manager.cc
index f172ee0..aaa6600 100644
--- a/runtime/oat_file_manager.cc
+++ b/runtime/oat_file_manager.cc
@@ -497,7 +497,6 @@
vdex_file = VdexFile::Open(vdex_path,
/* writable= */ false,
/* low_4gb= */ false,
- /* unquicken= */ false,
&error_msg);
if (vdex_file == nullptr) {
LOG(WARNING) << "Failed to open vdex " << vdex_path << ": " << error_msg;
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index 483e2ab..54e9d38 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -709,7 +709,9 @@
// Ensure that the threads in the JIT pool have been created with the right
// priority.
if (kIsDebugBuild && jit->GetThreadPool() != nullptr) {
- jit->GetThreadPool()->CheckPthreadPriority(jit->GetThreadPoolPthreadPriority());
+ jit->GetThreadPool()->CheckPthreadPriority(
+ IsZygote() ? jit->GetZygoteThreadPoolPthreadPriority()
+ : jit->GetThreadPoolPthreadPriority());
}
}
// Reset all stats.
@@ -1661,8 +1663,7 @@
// Change the implicit checks flags based on runtime architecture.
switch (kRuntimeISA) {
case InstructionSet::kArm64:
- // TODO: Investigate implicit suspend check regressions. Bug: 209235730, 213121241.
- implicit_suspend_checks_ = false;
+ implicit_suspend_checks_ = true;
FALLTHROUGH_INTENDED;
case InstructionSet::kArm:
case InstructionSet::kThumb2:
diff --git a/runtime/thread-inl.h b/runtime/thread-inl.h
index fc8e6cb..3c1e7a0 100644
--- a/runtime/thread-inl.h
+++ b/runtime/thread-inl.h
@@ -46,7 +46,7 @@
PoisonObjectPointers();
}
-inline void Thread::CheckSuspend() {
+inline void Thread::CheckSuspend(bool implicit) {
DCHECK_EQ(Thread::Current(), this);
while (true) {
StateAndFlags state_and_flags = GetStateAndFlags(std::memory_order_relaxed);
@@ -55,12 +55,18 @@
} else if (state_and_flags.IsFlagSet(ThreadFlag::kCheckpointRequest)) {
RunCheckpointFunction();
} else if (state_and_flags.IsFlagSet(ThreadFlag::kSuspendRequest)) {
- FullSuspendCheck();
+ FullSuspendCheck(implicit);
+ implicit = false; // We do not need to `MadviseAwayAlternateSignalStack()` anymore.
} else {
DCHECK(state_and_flags.IsFlagSet(ThreadFlag::kEmptyCheckpointRequest));
RunEmptyCheckpoint();
}
}
+ if (implicit) {
+ // For implicit suspend check we want to `madvise()` away
+ // the alternate signal stack to avoid wasting memory.
+ MadviseAwayAlternateSignalStack();
+ }
}
inline void Thread::CheckEmptyCheckpointFromWeakRefAccess(BaseMutex* cond_var_mutex) {
diff --git a/runtime/thread.cc b/runtime/thread.cc
index 7988f88..25d493f 100644
--- a/runtime/thread.cc
+++ b/runtime/thread.cc
@@ -1861,12 +1861,17 @@
}
}
-void Thread::FullSuspendCheck() {
+void Thread::FullSuspendCheck(bool implicit) {
ScopedTrace trace(__FUNCTION__);
VLOG(threads) << this << " self-suspending";
// Make thread appear suspended to other threads, release mutator_lock_.
// Transition to suspended and back to runnable, re-acquire share on mutator_lock_.
ScopedThreadSuspension(this, ThreadState::kSuspended); // NOLINT
+ if (implicit) {
+ // For implicit suspend check we want to `madvise()` away
+ // the alternate signal stack to avoid wasting memory.
+ MadviseAwayAlternateSignalStack();
+ }
VLOG(threads) << this << " self-reviving";
}
diff --git a/runtime/thread.h b/runtime/thread.h
index 3c358d8..1085a56 100644
--- a/runtime/thread.h
+++ b/runtime/thread.h
@@ -230,7 +230,7 @@
void AllowThreadSuspension() REQUIRES_SHARED(Locks::mutator_lock_);
// Process pending thread suspension request and handle if pending.
- void CheckSuspend() REQUIRES_SHARED(Locks::mutator_lock_);
+ void CheckSuspend(bool implicit = false) REQUIRES_SHARED(Locks::mutator_lock_);
// Process a pending empty checkpoint if pending.
void CheckEmptyCheckpointFromWeakRefAccess(BaseMutex* cond_var_mutex);
@@ -367,7 +367,7 @@
// Called when thread detected that the thread_suspend_count_ was non-zero. Gives up share of
// mutator_lock_ and waits until it is resumed and thread_suspend_count_ is zero.
- void FullSuspendCheck()
+ void FullSuspendCheck(bool implicit = false)
REQUIRES(!Locks::thread_suspend_count_lock_)
REQUIRES_SHARED(Locks::mutator_lock_);
@@ -1479,6 +1479,7 @@
void SetUpAlternateSignalStack();
void TearDownAlternateSignalStack();
+ void MadviseAwayAlternateSignalStack();
ALWAYS_INLINE void TransitionToSuspendedAndRunCheckpoints(ThreadState new_state)
REQUIRES(!Locks::thread_suspend_count_lock_, !Roles::uninterruptible_)
diff --git a/runtime/thread_android.cc b/runtime/thread_android.cc
index f333400..fadfc09 100644
--- a/runtime/thread_android.cc
+++ b/runtime/thread_android.cc
@@ -14,6 +14,9 @@
* limitations under the License.
*/
+#include <signal.h>
+#include <sys/mman.h>
+
#include "thread.h"
namespace art {
@@ -26,4 +29,12 @@
// Bionic does this for us.
}
+void Thread::MadviseAwayAlternateSignalStack() {
+ stack_t old_ss;
+ int result = sigaltstack(nullptr, &old_ss);
+ CHECK_EQ(result, 0);
+ result = madvise(old_ss.ss_sp, old_ss.ss_size, MADV_FREE);
+ CHECK_EQ(result, 0);
+}
+
} // namespace art
diff --git a/runtime/thread_linux.cc b/runtime/thread_linux.cc
index 3ed4276..afce796 100644
--- a/runtime/thread_linux.cc
+++ b/runtime/thread_linux.cc
@@ -70,4 +70,8 @@
delete[] allocated_signal_stack;
}
+void Thread::MadviseAwayAlternateSignalStack() {
+ // We do not `madvise()` away the alternate signal stack on host.
+}
+
} // namespace art
diff --git a/runtime/vdex_file.cc b/runtime/vdex_file.cc
index 1bf6493..77647fb 100644
--- a/runtime/vdex_file.cc
+++ b/runtime/vdex_file.cc
@@ -75,7 +75,6 @@
const std::string& vdex_filename,
bool writable,
bool low_4gb,
- bool unquicken,
std::string* error_msg) {
ScopedTrace trace(("VdexFile::OpenAtAddress " + vdex_filename).c_str());
if (!OS::FileExists(vdex_filename.c_str())) {
@@ -109,7 +108,6 @@
vdex_filename,
writable,
low_4gb,
- unquicken,
error_msg);
}
@@ -121,7 +119,6 @@
const std::string& vdex_filename,
bool writable,
bool low_4gb,
- bool unquicken,
std::string* error_msg) {
if (mmap_addr != nullptr && mmap_size < vdex_length) {
*error_msg = StringPrintf("Insufficient pre-allocated space to mmap vdex: %zu and %zu",
@@ -130,7 +127,6 @@
return nullptr;
}
CHECK(!mmap_reuse || mmap_addr != nullptr);
- CHECK(!(writable && unquicken)) << "We don't want to be writing unquickened files out to disk!";
// Start as PROT_WRITE so we can mprotect back to it if we want to.
MemMap mmap = MemMap::MapFileAtAddress(
mmap_addr,
diff --git a/runtime/vdex_file.h b/runtime/vdex_file.h
index 35be4fb..3ccbfa5 100644
--- a/runtime/vdex_file.h
+++ b/runtime/vdex_file.h
@@ -194,7 +194,6 @@
const std::string& vdex_filename,
bool writable,
bool low_4gb,
- bool unquicken,
std::string* error_msg);
// Returns nullptr if the vdex file cannot be opened or is not valid.
@@ -207,14 +206,12 @@
const std::string& vdex_filename,
bool writable,
bool low_4gb,
- bool unquicken,
std::string* error_msg);
// Returns nullptr if the vdex file cannot be opened or is not valid.
static std::unique_ptr<VdexFile> Open(const std::string& vdex_filename,
bool writable,
bool low_4gb,
- bool unquicken,
std::string* error_msg) {
return OpenAtAddress(nullptr,
0,
@@ -222,7 +219,6 @@
vdex_filename,
writable,
low_4gb,
- unquicken,
error_msg);
}
@@ -232,7 +228,6 @@
const std::string& vdex_filename,
bool writable,
bool low_4gb,
- bool unquicken,
std::string* error_msg) {
return OpenAtAddress(nullptr,
0,
@@ -242,7 +237,6 @@
vdex_filename,
writable,
low_4gb,
- unquicken,
error_msg);
}
diff --git a/runtime/vdex_file_test.cc b/runtime/vdex_file_test.cc
index 9d92b42..565487e 100644
--- a/runtime/vdex_file_test.cc
+++ b/runtime/vdex_file_test.cc
@@ -36,12 +36,11 @@
tmp.GetFilename(),
/*writable=*/false,
/*low_4gb=*/false,
- /*unquicken=*/false,
&error_msg);
EXPECT_TRUE(vdex == nullptr);
vdex = VdexFile::Open(
- tmp.GetFilename(), /*writable=*/false, /*low_4gb=*/false, /*unquicken=*/ false, &error_msg);
+ tmp.GetFilename(), /*writable=*/false, /*low_4gb=*/false, &error_msg);
EXPECT_TRUE(vdex == nullptr);
}
diff --git a/test/706-checker-scheduler/src/Main.java b/test/706-checker-scheduler/src/Main.java
index dc07a08..1b8377d 100644
--- a/test/706-checker-scheduler/src/Main.java
+++ b/test/706-checker-scheduler/src/Main.java
@@ -610,10 +610,10 @@
/// CHECK: beq
/// CHECK-START-ARM64: void Main.testCrossItersDependencies() disassembly (after)
- /// CHECK: ldr
/// CHECK: sub
/// CHECK: add
/// CHECK: add
+ /// CHECK: ldr
/// CHECK: b
private static void testCrossItersDependencies() {
int[] data = {1, 2, 3, 0};
diff --git a/test/dexpreopt/dexpreopt_test.cc b/test/dexpreopt/dexpreopt_test.cc
index 2dd5662..5315937 100644
--- a/test/dexpreopt/dexpreopt_test.cc
+++ b/test/dexpreopt/dexpreopt_test.cc
@@ -28,12 +28,16 @@
#include <iterator>
#include <string>
#include <unordered_set>
+#include <utility>
#include <vector>
+#include "android-base/properties.h"
#include "android-base/result.h"
+#include "android-base/stringprintf.h"
#include "android-base/strings.h"
#include "arch/instruction_set.h"
#include "base/common_art_test.h"
+#include "base/file_utils.h"
#include "base/os.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
@@ -44,6 +48,9 @@
using ::testing::IsSubsetOf;
+constexpr const char* kZygote32 = "zygote";
+constexpr const char* kZygote64 = "zygote64";
+
std::vector<std::string> GetListFromEnv(const std::string& name) {
const char* env_value = getenv(name.c_str());
if (env_value == nullptr || strlen(env_value) == 0) {
@@ -52,7 +59,74 @@
return android::base::Split(env_value, ":");
}
-android::base::Result<std::vector<std::string>> GetSystemServerArtifacts() {
+android::base::Result<std::vector<std::pair<std::string, InstructionSet>>> GetZygoteNamesAndIsas() {
+ std::vector<std::pair<std::string, InstructionSet>> names_and_isas;
+
+ // Possible values are: "zygote32", "zygote64", "zygote32_64", "zygote64_32".
+ std::string zygote_kinds = android::base::GetProperty("ro.zygote", {});
+ if (zygote_kinds.empty()) {
+ return Errorf("Unable to get Zygote kinds");
+ }
+
+ switch (kRuntimeISA) {
+ case InstructionSet::kArm:
+ case InstructionSet::kArm64:
+ if (zygote_kinds.find("32") != std::string::npos) {
+ names_and_isas.push_back(std::make_pair(kZygote32, InstructionSet::kArm));
+ }
+ if (zygote_kinds.find("64") != std::string::npos) {
+ names_and_isas.push_back(std::make_pair(kZygote64, InstructionSet::kArm64));
+ }
+ break;
+ case InstructionSet::kX86:
+ case InstructionSet::kX86_64:
+ if (zygote_kinds.find("32") != std::string::npos) {
+ names_and_isas.push_back(std::make_pair(kZygote32, InstructionSet::kX86));
+ }
+ if (zygote_kinds.find("64") != std::string::npos) {
+ names_and_isas.push_back(std::make_pair(kZygote64, InstructionSet::kX86_64));
+ }
+ break;
+ default:
+ return Errorf("Unknown runtime ISA: {}", GetInstructionSetString(kRuntimeISA));
+ }
+
+ return names_and_isas;
+}
+
+android::base::Result<std::vector<std::string>> GetZygoteExpectedArtifacts(InstructionSet isa) {
+ std::vector<std::string> jars = GetListFromEnv("DEX2OATBOOTCLASSPATH");
+ if (jars.empty()) {
+ return Errorf("Environment variable `DEX2OATBOOTCLASSPATH` is not defined or empty");
+ }
+ std::string art_root = GetArtRoot();
+ std::string android_root = GetAndroidRoot();
+ std::vector<std::string> artifacts;
+ for (size_t i = 0; i < jars.size(); i++) {
+ const std::string& jar = jars[i];
+ std::string basename =
+ i == 0 ? "boot.oat" : "boot-" + ReplaceFileExtension(android::base::Basename(jar), "oat");
+ // TODO(b/211973309): Update this once the primary boot image is moved.
+ std::string dir = android::base::StartsWith(jar, art_root) ? art_root + "/javalib" :
+ android_root + "/framework";
+ std::string oat_file = android::base::StringPrintf(
+ "%s/%s/%s", dir.c_str(), GetInstructionSetString(isa), basename.c_str());
+
+ if (!OS::FileExists(oat_file.c_str())) {
+ if (errno == EACCES) {
+ return ErrnoErrorf("Failed to stat() {}", oat_file);
+ }
+ // Dexpreopting is probably disabled. No need to report missing artifacts here because
+ // artifact generation is already checked at build time.
+ continue;
+ }
+
+ artifacts.push_back(oat_file);
+ }
+ return artifacts;
+}
+
+android::base::Result<std::vector<std::string>> GetSystemServerExpectedArtifacts() {
std::vector<std::string> jars = GetListFromEnv("SYSTEMSERVERCLASSPATH");
if (jars.empty()) {
return Errorf("Environment variable `SYSTEMSERVERCLASSPATH` is not defined or empty");
@@ -85,31 +159,76 @@
return artifacts;
}
+android::base::Result<std::vector<std::string>> GetMappedFiles(pid_t pid,
+ const std::string& extension,
+ uint16_t flags) {
+ std::vector<android::procinfo::MapInfo> maps;
+ if (!android::procinfo::ReadProcessMaps(pid, &maps)) {
+ return ErrnoErrorf("Failed to get mapped memory regions of pid {}", pid);
+ }
+ std::vector<std::string> files;
+ for (const android::procinfo::MapInfo& map : maps) {
+ if ((map.flags & flags) && android::base::EndsWith(map.name, extension)) {
+ files.push_back(map.name);
+ }
+ }
+ return files;
+}
+
+android::base::Result<std::vector<std::string>> GetZygoteMappedOatFiles(
+ const std::string& zygote_name) {
+ std::vector<pid_t> pids = art::GetPidByName(zygote_name);
+ if (pids.empty()) {
+ return Errorf("Unable to find Zygote process: {}", zygote_name);
+ }
+ // OAT files in boot images may not be mmaped with PROT_EXEC if they don't contain executable
+ // code. Checking PROT_READ is sufficient because an OAT file will be unmapped if the runtime
+ // rejects it.
+ return GetMappedFiles(pids[0], ".oat", PROT_READ);
+}
+
android::base::Result<std::vector<std::string>> GetSystemServerArtifactsMappedOdexes() {
std::vector<pid_t> pids = art::GetPidByName("system_server");
if (pids.size() != 1) {
return Errorf("There should be exactly one `system_server` process, found {}", pids.size());
}
- pid_t pid = pids[0];
- std::vector<android::procinfo::MapInfo> maps;
- if (!android::procinfo::ReadProcessMaps(pid, &maps)) {
- return ErrnoErrorf("Failed to get mapped memory regions of `system_server`");
- }
- std::vector<std::string> odexes;
- for (const android::procinfo::MapInfo& map : maps) {
- if ((map.flags & PROT_EXEC) && android::base::EndsWith(map.name, ".odex")) {
- odexes.push_back(map.name);
+ // Unlike boot images, app images don't get unmapped if the runtime rejects them in some cases
+ // (e.g., CLC mismatch). Therefore, we need to check the PROT_EXEC flag to ensure that they are
+ // valid.
+ // The ODEX files always contain executable code because system server jars are compiled with the
+ // "speed" filter.
+ return GetMappedFiles(pids[0], ".odex", PROT_EXEC);
+}
+
+TEST(DexpreoptTest, ForZygote) {
+ android::base::Result<std::vector<std::pair<std::string, InstructionSet>>> zygote_names_and_isas =
+ GetZygoteNamesAndIsas();
+ ASSERT_RESULT_OK(zygote_names_and_isas);
+
+ for (const auto& [zygote_name, isa] : *zygote_names_and_isas) {
+ android::base::Result<std::vector<std::string>> expected_artifacts =
+ GetZygoteExpectedArtifacts(isa);
+ ASSERT_RESULT_OK(expected_artifacts);
+
+ if (expected_artifacts->empty()) {
+ // Skip the test if dexpreopting is disabled.
+ return;
}
+
+ android::base::Result<std::vector<std::string>> mapped_oat_files =
+ GetZygoteMappedOatFiles(zygote_name);
+ ASSERT_RESULT_OK(mapped_oat_files);
+
+ EXPECT_THAT(expected_artifacts.value(), IsSubsetOf(mapped_oat_files.value()));
}
- return odexes;
}
TEST(DexpreoptTest, ForSystemServer) {
- android::base::Result<std::vector<std::string>> system_server_artifacts =
- GetSystemServerArtifacts();
- ASSERT_RESULT_OK(system_server_artifacts);
+ android::base::Result<std::vector<std::string>> expected_artifacts =
+ GetSystemServerExpectedArtifacts();
+ ASSERT_RESULT_OK(expected_artifacts);
- if (system_server_artifacts->empty()) {
+ if (expected_artifacts->empty()) {
// Skip the test if dexpreopting is disabled.
return;
}
@@ -118,7 +237,7 @@
GetSystemServerArtifactsMappedOdexes();
ASSERT_RESULT_OK(mapped_odexes);
- EXPECT_THAT(system_server_artifacts.value(), IsSubsetOf(mapped_odexes.value()));
+ EXPECT_THAT(expected_artifacts.value(), IsSubsetOf(mapped_odexes.value()));
}
} // namespace art
diff --git a/test/odsign/src/com/android/tests/odsign/ArtifactsSignedTest.java b/test/odsign/src/com/android/tests/odsign/ArtifactsSignedTest.java
index 25a46e3..f29baa7 100644
--- a/test/odsign/src/com/android/tests/odsign/ArtifactsSignedTest.java
+++ b/test/odsign/src/com/android/tests/odsign/ArtifactsSignedTest.java
@@ -43,9 +43,9 @@
// Verifying that they are generated for the correct architectures is currently out of
// scope for this test.
private static final String[] REQUIRED_ARTIFACT_NAMES = {
- "boot-framework.art",
- "boot-framework.oat",
- "boot-framework.vdex",
+ "boot.art",
+ "boot.oat",
+ "boot.vdex",
"system@framework@services.jar@classes.vdex",
"system@framework@services.jar@classes.odex",
"system@framework@services.jar@classes.art",
diff --git a/test/odsign/test-src/com/android/tests/odsign/OdsignTestUtils.java b/test/odsign/test-src/com/android/tests/odsign/OdsignTestUtils.java
index 101e5e2..f00ff14 100644
--- a/test/odsign/test-src/com/android/tests/odsign/OdsignTestUtils.java
+++ b/test/odsign/test-src/com/android/tests/odsign/OdsignTestUtils.java
@@ -106,7 +106,7 @@
final String zygotePid = result.getStdout().trim().split("\\s+")[0];
assertTrue(!zygotePid.isEmpty());
- final String grepPattern = ART_APEX_DALVIK_CACHE_DIRNAME + ".*boot-framework";
+ final String grepPattern = ART_APEX_DALVIK_CACHE_DIRNAME + ".*boot";
return Optional.of(getMappedArtifacts(zygotePid, grepPattern));
}
diff --git a/test/odsign/test-src/com/android/tests/odsign/OnDeviceSigningHostTest.java b/test/odsign/test-src/com/android/tests/odsign/OnDeviceSigningHostTest.java
index bcce9a0..9c1949c 100644
--- a/test/odsign/test-src/com/android/tests/odsign/OnDeviceSigningHostTest.java
+++ b/test/odsign/test-src/com/android/tests/odsign/OnDeviceSigningHostTest.java
@@ -118,8 +118,6 @@
private String getSystemServerIsa(String mappedArtifact) {
// Artifact path for system server artifacts has the form:
// ART_APEX_DALVIK_CACHE_DIRNAME + "/<arch>/system@framework@some.jar@classes.odex"
- // `mappedArtifacts` may include other artifacts, such as boot-framework.oat that are not
- // prefixed by the architecture.
String[] pathComponents = mappedArtifact.split("/");
return pathComponents[pathComponents.length - 2];
}
@@ -161,13 +159,13 @@
private void verifyZygoteLoadedArtifacts(String zygoteName, Set<String> mappedArtifacts)
throws Exception {
- final String bootExtensionName = "boot-framework";
+ final String bootImageStem = "boot";
- assertTrue("Expect 3 boot-framework artifacts", mappedArtifacts.size() == 3);
+ assertTrue("Expect 3 bootclasspath artifacts", mappedArtifacts.size() == 3);
String allArtifacts = mappedArtifacts.stream().collect(Collectors.joining(","));
for (String extension : OdsignTestUtils.BCP_ARTIFACT_EXTENSIONS) {
- final String artifact = bootExtensionName + extension;
+ final String artifact = bootImageStem + extension;
final boolean found = mappedArtifacts.stream().anyMatch(a -> a.endsWith(artifact));
assertTrue(zygoteName + " " + artifact + " not found: '" + allArtifacts + "'", found);
}