Add runtime option -Xbootclasspathfds: for pre-opened fds
The new option allows the client to pass a pre-opened fds to the
runtime. The number of elements must match the number of BCP jars
specified in -Xbootclasspath. An fd of negative number is a valid
option, in such case the runtime will still open the jar in the
corresponding path in -Xbootclasspath.
Example: -Xbootclasspathfds:10:11:-1:12
The option is currently only used in "unstarted runtime", but will also
be used elsewhere in the follow-up changes.
Bug: 187327262
Test: patch odrefresh to use the option, no longer seeing such openat(2)
Test: m test-art-host-gtest
Change-Id: I1bebbd80136419c03ac1309a8cb8229a0fd69838
diff --git a/dex2oat/dex2oat_image_test.cc b/dex2oat/dex2oat_image_test.cc
index cfb79e5..e377308 100644
--- a/dex2oat/dex2oat_image_test.cc
+++ b/dex2oat/dex2oat_image_test.cc
@@ -422,6 +422,7 @@
ScopedObjectAccess soa(Thread::Current());
return gc::space::ImageSpace::LoadBootImage(/*boot_class_path=*/ boot_class_path,
/*boot_class_path_locations=*/ libcore_dex_files,
+ /*boot_class_path_fds=*/ std::vector<int>(),
android::base::Split(image_location, ":"),
kRuntimeISA,
relocate,
diff --git a/dexoptanalyzer/dexoptanalyzer.cc b/dexoptanalyzer/dexoptanalyzer.cc
index a6fcd02..92baff7 100644
--- a/dexoptanalyzer/dexoptanalyzer.cc
+++ b/dexoptanalyzer/dexoptanalyzer.cc
@@ -368,6 +368,7 @@
std::string error_msg;
const std::vector<std::string>& bcp = runtime->GetBootClassPath();
const std::vector<std::string>& bcp_locations = runtime->GetBootClassPathLocations();
+ const std::vector<int>& bcp_fds = runtime->GetBootClassPathFds();
const std::vector<std::string>& image_locations = runtime->GetImageLocations();
const std::string bcp_locations_path = android::base::Join(bcp_locations, ':');
if (!ImageSpace::VerifyBootClassPathChecksums(checksums,
@@ -375,6 +376,7 @@
ArrayRef<const std::string>(image_locations),
ArrayRef<const std::string>(bcp_locations),
ArrayRef<const std::string>(bcp),
+ ArrayRef<const int>(bcp_fds),
runtime->GetInstructionSet(),
&error_msg)) {
LOG(INFO) << "Failed to verify boot class path checksums: " << error_msg;
diff --git a/runtime/dexopt_test.cc b/runtime/dexopt_test.cc
index abde17c..f0b31cc 100644
--- a/runtime/dexopt_test.cc
+++ b/runtime/dexopt_test.cc
@@ -176,6 +176,7 @@
ArrayRef<const std::string>(&image_location, 1),
ArrayRef<const std::string>(Runtime::Current()->GetBootClassPathLocations()),
ArrayRef<const std::string>(Runtime::Current()->GetBootClassPath()),
+ ArrayRef<const int>(Runtime::Current()->GetBootClassPathFds()),
kRuntimeISA,
&error_msg);
ASSERT_EQ(!with_alternate_image, match) << error_msg;
diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc
index e84c436..4676ded 100644
--- a/runtime/gc/heap.cc
+++ b/runtime/gc/heap.cc
@@ -262,6 +262,7 @@
size_t non_moving_space_capacity,
const std::vector<std::string>& boot_class_path,
const std::vector<std::string>& boot_class_path_locations,
+ const std::vector<int>& boot_class_path_fds,
const std::vector<std::string>& image_file_names,
const InstructionSet image_instruction_set,
CollectorType foreground_collector_type,
@@ -462,6 +463,7 @@
MemMap heap_reservation;
if (space::ImageSpace::LoadBootImage(boot_class_path,
boot_class_path_locations,
+ boot_class_path_fds,
image_file_names,
image_instruction_set,
runtime->ShouldRelocate(),
diff --git a/runtime/gc/heap.h b/runtime/gc/heap.h
index 047af16..f9dd83d 100644
--- a/runtime/gc/heap.h
+++ b/runtime/gc/heap.h
@@ -201,6 +201,7 @@
size_t non_moving_space_capacity,
const std::vector<std::string>& boot_class_path,
const std::vector<std::string>& boot_class_path_locations,
+ const std::vector<int>& boot_class_path_fds,
const std::vector<std::string>& image_file_names,
InstructionSet image_instruction_set,
CollectorType foreground_collector_type,
diff --git a/runtime/gc/space/image_space.cc b/runtime/gc/space/image_space.cc
index 750256d..bd34df4 100644
--- a/runtime/gc/space/image_space.cc
+++ b/runtime/gc/space/image_space.cc
@@ -1413,10 +1413,12 @@
BootImageLayout(ArrayRef<const std::string> image_locations,
ArrayRef<const std::string> boot_class_path,
- ArrayRef<const std::string> boot_class_path_locations)
+ ArrayRef<const std::string> boot_class_path_locations,
+ ArrayRef<const int> boot_class_path_fds)
: image_locations_(image_locations),
boot_class_path_(boot_class_path),
- boot_class_path_locations_(boot_class_path_locations) {}
+ boot_class_path_locations_(boot_class_path_locations),
+ boot_class_path_fds_(boot_class_path_fds) {}
std::string GetPrimaryImageLocation();
@@ -1530,6 +1532,7 @@
ArrayRef<const std::string> image_locations_;
ArrayRef<const std::string> boot_class_path_;
ArrayRef<const std::string> boot_class_path_locations_;
+ ArrayRef<const int> boot_class_path_fds_;
std::vector<ImageChunk> chunks_;
uint32_t base_address_ = 0u;
@@ -2219,12 +2222,14 @@
public:
BootImageLoader(const std::vector<std::string>& boot_class_path,
const std::vector<std::string>& boot_class_path_locations,
+ const std::vector<int>& boot_class_path_fds,
const std::vector<std::string>& image_locations,
InstructionSet image_isa,
bool relocate,
bool executable)
: boot_class_path_(boot_class_path),
boot_class_path_locations_(boot_class_path_locations),
+ boot_class_path_fds_(boot_class_path_fds),
image_locations_(image_locations),
image_isa_(image_isa),
relocate_(relocate),
@@ -2233,7 +2238,10 @@
}
void FindImageFiles() {
- BootImageLayout layout(image_locations_, boot_class_path_, boot_class_path_locations_);
+ BootImageLayout layout(image_locations_,
+ boot_class_path_,
+ boot_class_path_locations_,
+ boot_class_path_fds_);
std::string image_location = layout.GetPrimaryImageLocation();
std::string system_filename;
bool found_image = FindImageFilenameImpl(image_location.c_str(),
@@ -3091,6 +3099,7 @@
const ArrayRef<const std::string> boot_class_path_;
const ArrayRef<const std::string> boot_class_path_locations_;
+ const ArrayRef<const int> boot_class_path_fds_;
const ArrayRef<const std::string> image_locations_;
const InstructionSet image_isa_;
const bool relocate_;
@@ -3105,7 +3114,10 @@
/*out*/std::string* error_msg) {
TimingLogger logger(__PRETTY_FUNCTION__, /*precise=*/ true, VLOG_IS_ON(image));
- BootImageLayout layout(image_locations_, boot_class_path_, boot_class_path_locations_);
+ BootImageLayout layout(image_locations_,
+ boot_class_path_,
+ boot_class_path_locations_,
+ boot_class_path_fds_);
if (!layout.LoadFromSystem(image_isa_, error_msg)) {
return false;
}
@@ -3132,7 +3144,8 @@
Runtime* runtime = Runtime::Current();
BootImageLayout layout(ArrayRef<const std::string>(runtime->GetImageLocations()),
ArrayRef<const std::string>(runtime->GetBootClassPath()),
- ArrayRef<const std::string>(runtime->GetBootClassPathLocations()));
+ ArrayRef<const std::string>(runtime->GetBootClassPathLocations()),
+ ArrayRef<const int>(runtime->GetBootClassPathFds()));
const std::string image_location = layout.GetPrimaryImageLocation();
std::unique_ptr<ImageHeader> image_header;
std::string error_msg;
@@ -3154,6 +3167,7 @@
bool ImageSpace::LoadBootImage(
const std::vector<std::string>& boot_class_path,
const std::vector<std::string>& boot_class_path_locations,
+ const std::vector<int>& boot_class_path_fds,
const std::vector<std::string>& image_locations,
const InstructionSet image_isa,
bool relocate,
@@ -3175,6 +3189,7 @@
BootImageLoader loader(boot_class_path,
boot_class_path_locations,
+ boot_class_path_fds,
image_locations,
image_isa,
relocate,
@@ -3420,6 +3435,7 @@
ArrayRef<const std::string> image_locations,
ArrayRef<const std::string> boot_class_path_locations,
ArrayRef<const std::string> boot_class_path,
+ ArrayRef<const int> boot_class_path_fds,
InstructionSet image_isa,
/*out*/std::string* error_msg) {
if (oat_checksums.empty() || oat_boot_class_path.empty()) {
@@ -3437,10 +3453,15 @@
size_t bcp_pos = 0u;
if (StartsWith(oat_checksums, "i")) {
- // Use only the matching part of the BCP for validation.
+ // Use only the matching part of the BCP for validation. FDs are optional, so only pass the
+ // sub-array if provided.
+ ArrayRef<const int> bcp_fds = boot_class_path_fds.empty()
+ ? ArrayRef<const int>()
+ : boot_class_path_fds.SubArray(/*pos=*/ 0u, bcp_size);
BootImageLayout layout(image_locations,
boot_class_path.SubArray(/*pos=*/ 0u, bcp_size),
- boot_class_path_locations.SubArray(/*pos=*/ 0u, bcp_size));
+ boot_class_path_locations.SubArray(/*pos=*/ 0u, bcp_size),
+ bcp_fds);
std::string primary_image_location = layout.GetPrimaryImageLocation();
std::string system_filename;
bool has_system = false;
diff --git a/runtime/gc/space/image_space.h b/runtime/gc/space/image_space.h
index aa93247..c8879cb 100644
--- a/runtime/gc/space/image_space.h
+++ b/runtime/gc/space/image_space.h
@@ -124,6 +124,7 @@
static bool LoadBootImage(
const std::vector<std::string>& boot_class_path,
const std::vector<std::string>& boot_class_path_locations,
+ const std::vector<int>& boot_class_path_fds,
const std::vector<std::string>& image_locations,
const InstructionSet image_isa,
bool relocate,
@@ -236,6 +237,7 @@
ArrayRef<const std::string> image_locations,
ArrayRef<const std::string> boot_class_path_locations,
ArrayRef<const std::string> boot_class_path,
+ ArrayRef<const int> boot_class_path_fds,
InstructionSet image_isa,
/*out*/std::string* error_msg);
diff --git a/runtime/gc/space/image_space_test.cc b/runtime/gc/space/image_space_test.cc
index 1a53efa..58be15d 100644
--- a/runtime/gc/space/image_space_test.cc
+++ b/runtime/gc/space/image_space_test.cc
@@ -136,6 +136,7 @@
extra_reservation = MemMap::Invalid();
return ImageSpace::LoadBootImage(bcp,
bcp_locations,
+ /*boot_class_path_fds=*/ std::vector<int>(),
full_image_locations,
kRuntimeISA,
/*relocate=*/ false,
@@ -336,6 +337,7 @@
ArrayRef<const std::string>(runtime->GetImageLocations()),
ArrayRef<const std::string>(bcp_locations),
ArrayRef<const std::string>(bcp),
+ /*boot_class_path_fds=*/ ArrayRef<const int>(),
kRuntimeISA,
&error_msg);
};
diff --git a/runtime/interpreter/unstarted_runtime.cc b/runtime/interpreter/unstarted_runtime.cc
index 73fffe8..9ed3b5e 100644
--- a/runtime/interpreter/unstarted_runtime.cc
+++ b/runtime/interpreter/unstarted_runtime.cc
@@ -485,12 +485,18 @@
}
static MemMap FindAndExtractEntry(const std::string& jar_file,
+ int jar_fd,
const char* entry_name,
size_t* size,
std::string* error_msg) {
CHECK(size != nullptr);
- std::unique_ptr<ZipArchive> zip_archive(ZipArchive::Open(jar_file.c_str(), error_msg));
+ std::unique_ptr<ZipArchive> zip_archive;
+ if (jar_fd >= 0) {
+ zip_archive.reset(ZipArchive::OpenFromFd(jar_fd, jar_file.c_str(), error_msg));
+ } else {
+ zip_archive.reset(ZipArchive::Open(jar_file.c_str(), error_msg));
+ }
if (zip_archive == nullptr) {
return MemMap::Invalid();
}
@@ -540,12 +546,18 @@
return;
}
+ const std::vector<int>& boot_class_path_fds = Runtime::Current()->GetBootClassPathFds();
+ DCHECK(boot_class_path_fds.empty() || boot_class_path_fds.size() == boot_class_path.size());
+
MemMap mem_map;
size_t map_size;
std::string last_error_msg; // Only store the last message (we could concatenate).
- for (const std::string& jar_file : boot_class_path) {
- mem_map = FindAndExtractEntry(jar_file, resource_cstr, &map_size, &last_error_msg);
+ bool has_bcp_fds = !boot_class_path_fds.empty();
+ for (size_t i = 0; i < boot_class_path.size(); ++i) {
+ const std::string& jar_file = boot_class_path[i];
+ const int jar_fd = has_bcp_fds ? boot_class_path_fds[i] : -1;
+ mem_map = FindAndExtractEntry(jar_file, jar_fd, resource_cstr, &map_size, &last_error_msg);
if (mem_map.IsValid()) {
break;
}
diff --git a/runtime/oat_file_assistant.cc b/runtime/oat_file_assistant.cc
index d176eb6..f323647 100644
--- a/runtime/oat_file_assistant.cc
+++ b/runtime/oat_file_assistant.cc
@@ -652,6 +652,7 @@
ArrayRef<const std::string>(runtime->GetImageLocations()),
ArrayRef<const std::string>(runtime->GetBootClassPathLocations()),
ArrayRef<const std::string>(runtime->GetBootClassPath()),
+ ArrayRef<const int>(runtime->GetBootClassPathFds()),
isa_,
&error_msg);
if (!result) {
diff --git a/runtime/parsed_options.cc b/runtime/parsed_options.cc
index 38552c6..cbee356 100644
--- a/runtime/parsed_options.cc
+++ b/runtime/parsed_options.cc
@@ -112,6 +112,9 @@
.Define("-Xbootclasspath:_")
.WithType<ParseStringList<':'>>() // std::vector<std::string>, split by :
.IntoKey(M::BootClassPath)
+ .Define("-Xbootclasspathfds:_")
+ .WithType<ParseIntList<':'>>()
+ .IntoKey(M::BootClassPathFds)
.Define("-Xcheck:jni")
.IntoKey(M::CheckJni)
.Define("-Xms_")
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index 35b7055..d54ef6b 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -1394,6 +1394,13 @@
}
}
+ boot_class_path_fds_ = runtime_options.ReleaseOrDefault(Opt::BootClassPathFds);
+ if (!boot_class_path_fds_.empty() && boot_class_path_fds_.size() != boot_class_path_.size()) {
+ LOG(ERROR) << "Number of FDs specified in -Xbootclasspathfds must match the number of JARs in "
+ << "-Xbootclasspath.";
+ return false;
+ }
+
class_path_string_ = runtime_options.ReleaseOrDefault(Opt::ClassPath);
properties_ = runtime_options.ReleaseOrDefault(Opt::PropertiesList);
@@ -1517,6 +1524,7 @@
runtime_options.GetOrDefault(Opt::NonMovingSpaceCapacity),
GetBootClassPath(),
GetBootClassPathLocations(),
+ GetBootClassPathFds(),
image_locations_,
instruction_set_,
// Override the collector type to CC if the read barrier config.
diff --git a/runtime/runtime.h b/runtime/runtime.h
index cdaf1ed..f399849 100644
--- a/runtime/runtime.h
+++ b/runtime/runtime.h
@@ -286,6 +286,10 @@
return boot_class_path_locations_.empty() ? boot_class_path_ : boot_class_path_locations_;
}
+ const std::vector<int>& GetBootClassPathFds() const {
+ return boot_class_path_fds_;
+ }
+
const std::string& GetClassPathString() const {
return class_path_string_;
}
@@ -1105,6 +1109,7 @@
std::vector<std::string> boot_class_path_;
std::vector<std::string> boot_class_path_locations_;
+ std::vector<int> boot_class_path_fds_;
std::string class_path_string_;
std::vector<std::string> properties_;
diff --git a/runtime/runtime_options.def b/runtime/runtime_options.def
index 7be2fa4..3717fbf 100644
--- a/runtime/runtime_options.def
+++ b/runtime/runtime_options.def
@@ -40,6 +40,7 @@
RUNTIME_OPTIONS_KEY (Unit, ShowVersion)
RUNTIME_OPTIONS_KEY (ParseStringList<':'>,BootClassPath) // std::vector<std::string>
RUNTIME_OPTIONS_KEY (ParseStringList<':'>,BootClassPathLocations) // std::vector<std::string>
+RUNTIME_OPTIONS_KEY (ParseIntList<':'>, BootClassPathFds) // std::vector<int>
RUNTIME_OPTIONS_KEY (std::string, ClassPath)
RUNTIME_OPTIONS_KEY (ParseStringList<':'>,Image)
RUNTIME_OPTIONS_KEY (Unit, CheckJni)