Revert^2 "Pass boot class path to ImageSpace::LoadBootImage."
This reverts commit db4b1deebf425be5f1d0f597d1ef540f19908324.
Fixed JDWP tests, see "Test:" stanzas below.
Change-Id: I6fb56ac990b78164cbd3f93c9f6df66e0dd9a813
Test: m test-art-host-gtest
Test: testrunner.py --host --optimizing
Test: Pixel 2 XL boots.
Test: m test-art-target-gtest
Test: testrunner.py --target --optimizing
Test: run-libcore-tests.sh --mode=device --variant=X64
Test: run-jdwp-tests.sh --mode=host --variant=X64
Test: run-jdwp-tests.sh --mode=device --variant=X64
Bug: 119868597
diff --git a/cmdline/cmdline_parser_test.cc b/cmdline/cmdline_parser_test.cc
index 97daafa..101e5c4 100644
--- a/cmdline/cmdline_parser_test.cc
+++ b/cmdline/cmdline_parser_test.cc
@@ -63,6 +63,12 @@
return expected == actual;
}
+ template <char Separator>
+ bool UsuallyEquals(const std::vector<std::string>& expected,
+ const ParseStringList<Separator>& actual) {
+ return expected == static_cast<std::vector<std::string>>(actual);
+ }
+
// Try to use memcmp to compare simple plain-old-data structs.
//
// This should *not* generate false positives, but it can generate false negatives.
@@ -218,8 +224,13 @@
}
EXPECT_SINGLE_PARSE_EXISTS("-Xzygote", M::Zygote);
- EXPECT_SINGLE_PARSE_VALUE_STR("/hello/world", "-Xbootclasspath:/hello/world", M::BootClassPath);
- EXPECT_SINGLE_PARSE_VALUE("/hello/world", "-Xbootclasspath:/hello/world", M::BootClassPath);
+ EXPECT_SINGLE_PARSE_VALUE(std::vector<std::string>({"/hello/world"}),
+ "-Xbootclasspath:/hello/world",
+ M::BootClassPath);
+ EXPECT_SINGLE_PARSE_VALUE(std::vector<std::string>({"/hello", "/world"}),
+ "-Xbootclasspath:/hello:/world",
+ M::BootClassPath);
+ EXPECT_SINGLE_PARSE_VALUE_STR("/hello/world", "-classpath /hello/world", M::ClassPath);
EXPECT_SINGLE_PARSE_VALUE(Memory<1>(234), "-Xss234", M::StackSize);
EXPECT_SINGLE_PARSE_VALUE(MemoryKiB(1234*MB), "-Xms1234m", M::MemoryInitialSize);
EXPECT_SINGLE_PARSE_VALUE(true, "-XX:EnableHSpaceCompactForOOM", M::EnableHSpaceCompactForOOM);
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index f729934..a5bba9b 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -103,6 +103,7 @@
using android::base::StringAppendV;
using android::base::StringPrintf;
+using gc::space::ImageSpace;
static constexpr size_t kDefaultMinDexFilesForSwap = 2;
static constexpr size_t kDefaultMinDexFileCumulativeSizeForSwap = 20 * MB;
@@ -964,89 +965,22 @@
}
void ExpandOatAndImageFilenames() {
- std::string base_oat = oat_filenames_[0];
- size_t last_oat_slash = base_oat.rfind('/');
- if (last_oat_slash == std::string::npos) {
- Usage("Unusable boot image oat filename %s", base_oat.c_str());
+ if (image_filenames_[0].rfind('/') == std::string::npos) {
+ Usage("Unusable boot image filename %s", image_filenames_[0].c_str());
}
- // We also need to honor path components that were encoded through '@'. Otherwise the loading
- // code won't be able to find the images.
- if (base_oat.find('@', last_oat_slash) != std::string::npos) {
- last_oat_slash = base_oat.rfind('@');
- }
- base_oat = base_oat.substr(0, last_oat_slash + 1);
+ image_filenames_ = ImageSpace::ExpandMultiImageLocations(dex_locations_, image_filenames_[0]);
- std::string base_img = image_filenames_[0];
- size_t last_img_slash = base_img.rfind('/');
- if (last_img_slash == std::string::npos) {
- Usage("Unusable boot image filename %s", base_img.c_str());
+ if (oat_filenames_[0].rfind('/') == std::string::npos) {
+ Usage("Unusable boot image oat filename %s", oat_filenames_[0].c_str());
}
- // We also need to honor path components that were encoded through '@'. Otherwise the loading
- // code won't be able to find the images.
- if (base_img.find('@', last_img_slash) != std::string::npos) {
- last_img_slash = base_img.rfind('@');
- }
+ oat_filenames_ = ImageSpace::ExpandMultiImageLocations(dex_locations_, oat_filenames_[0]);
- // Get the prefix, which is the primary image name (without path components). Strip the
- // extension.
- std::string prefix = base_img.substr(last_img_slash + 1);
- if (prefix.rfind('.') != std::string::npos) {
- prefix = prefix.substr(0, prefix.rfind('.'));
- }
- if (!prefix.empty()) {
- prefix = prefix + "-";
- }
-
- base_img = base_img.substr(0, last_img_slash + 1);
-
- std::string base_symbol_oat;
if (!oat_unstripped_.empty()) {
- base_symbol_oat = oat_unstripped_[0];
- size_t last_symbol_oat_slash = base_symbol_oat.rfind('/');
- if (last_symbol_oat_slash == std::string::npos) {
- Usage("Unusable boot image symbol filename %s", base_symbol_oat.c_str());
+ if (oat_unstripped_[0].rfind('/') == std::string::npos) {
+ Usage("Unusable boot image symbol filename %s", oat_unstripped_[0].c_str());
}
- base_symbol_oat = base_symbol_oat.substr(0, last_symbol_oat_slash + 1);
+ oat_unstripped_ = ImageSpace::ExpandMultiImageLocations(dex_locations_, oat_unstripped_[0]);
}
-
- // Now create the other names. Use a counted loop to skip the first one.
- for (size_t i = 1; i < dex_locations_.size(); ++i) {
- // TODO: Make everything properly std::string.
- std::string image_name = CreateMultiImageName(dex_locations_[i], prefix, ".art");
- char_backing_storage_.push_front(base_img + image_name);
- image_filenames_.push_back(char_backing_storage_.front().c_str());
-
- std::string oat_name = CreateMultiImageName(dex_locations_[i], prefix, ".oat");
- char_backing_storage_.push_front(base_oat + oat_name);
- oat_filenames_.push_back(char_backing_storage_.front().c_str());
-
- if (!base_symbol_oat.empty()) {
- char_backing_storage_.push_front(base_symbol_oat + oat_name);
- oat_unstripped_.push_back(char_backing_storage_.front().c_str());
- }
- }
- }
-
- // Modify the input string in the following way:
- // 0) Assume input is /a/b/c.d
- // 1) Strip the path -> c.d
- // 2) Inject prefix p -> pc.d
- // 3) Replace suffix with s if it's "jar" -> d == "jar" -> pc.s
- static std::string CreateMultiImageName(std::string in,
- const std::string& prefix,
- const char* replace_suffix) {
- size_t last_dex_slash = in.rfind('/');
- if (last_dex_slash != std::string::npos) {
- in = in.substr(last_dex_slash + 1);
- }
- if (!prefix.empty()) {
- in = prefix + in;
- }
- if (android::base::EndsWith(in, ".jar")) {
- in = in.substr(0, in.length() - strlen(".jar")) +
- (replace_suffix != nullptr ? replace_suffix : "");
- }
- return in;
}
void InsertCompileOptions(int argc, char** argv) {
@@ -1497,11 +1431,8 @@
if (IsBootImage()) {
// If we're compiling the boot image, store the boot classpath into the Key-Value store.
- // We need this for the multi-image case.
- key_value_store_->Put(OatHeader::kBootClassPathKey,
- gc::space::ImageSpace::GetMultiImageBootClassPath(dex_locations_,
- oat_filenames_,
- image_filenames_));
+ // We use this when loading the boot image.
+ key_value_store_->Put(OatHeader::kBootClassPathKey, android::base::Join(dex_locations_, ':'));
}
if (!IsBootImage()) {
@@ -1513,8 +1444,7 @@
if (CompilerFilter::DependsOnImageChecksum(compiler_options_->GetCompilerFilter())) {
TimingLogger::ScopedTiming t3("Loading image checksum", timings_);
- std::vector<gc::space::ImageSpace*> image_spaces =
- Runtime::Current()->GetHeap()->GetBootImageSpaces();
+ std::vector<ImageSpace*> image_spaces = Runtime::Current()->GetHeap()->GetBootImageSpaces();
boot_image_checksum_ = image_spaces[0]->GetImageHeader().GetImageChecksum();
} else {
boot_image_checksum_ = 0u;
@@ -1953,7 +1883,7 @@
if (IsImage()) {
if (IsAppImage() && image_base_ == 0) {
gc::Heap* const heap = Runtime::Current()->GetHeap();
- for (gc::space::ImageSpace* image_space : heap->GetBootImageSpaces()) {
+ for (ImageSpace* image_space : heap->GetBootImageSpaces()) {
image_base_ = std::max(image_base_, RoundUp(
reinterpret_cast<uintptr_t>(image_space->GetImageHeader().GetOatFileEnd()),
kPageSize));
diff --git a/dex2oat/linker/image_test.h b/dex2oat/linker/image_test.h
index 13fa0f0..bd8cf5a 100644
--- a/dex2oat/linker/image_test.h
+++ b/dex2oat/linker/image_test.h
@@ -169,10 +169,11 @@
{
// Create a generic tmp file, to be the base of the .art and .oat temporary files.
ScratchFile location;
- for (int i = 0; i < static_cast<int>(class_path.size()); ++i) {
- std::string cur_location =
- android::base::StringPrintf("%s-%d.art", location.GetFilename().c_str(), i);
- out_helper.image_locations.push_back(ScratchFile(cur_location));
+ std::vector<std::string> image_locations =
+ gc::space::ImageSpace::ExpandMultiImageLocations(out_helper.dex_file_locations,
+ location.GetFilename() + ".art");
+ for (size_t i = 0u; i != class_path.size(); ++i) {
+ out_helper.image_locations.push_back(ScratchFile(image_locations[i]));
}
}
std::vector<std::string> image_filenames;
@@ -223,10 +224,7 @@
TimingLogger::ScopedTiming t("WriteElf", &timings);
SafeMap<std::string, std::string> key_value_store;
key_value_store.Put(OatHeader::kBootClassPathKey,
- gc::space::ImageSpace::GetMultiImageBootClassPath(
- out_helper.dex_file_locations,
- oat_filenames,
- image_filenames));
+ android::base::Join(out_helper.dex_file_locations, ':'));
std::vector<std::unique_ptr<ElfWriter>> elf_writers;
std::vector<std::unique_ptr<OatWriter>> oat_writers;
diff --git a/oatdump/oatdump_test.h b/oatdump/oatdump_test.h
index 728939f..dfa659b 100644
--- a/oatdump/oatdump_test.h
+++ b/oatdump/oatdump_test.h
@@ -178,6 +178,11 @@
expected_prefixes.push_back("InlineInfo");
}
if (mode == kModeArt) {
+ exec_argv.push_back("--runtime-arg");
+ exec_argv.push_back(GetClassPathOption("-Xbootclasspath:", GetLibCoreDexFileNames()));
+ exec_argv.push_back("--runtime-arg");
+ exec_argv.push_back(
+ GetClassPathOption("-Xbootclasspath-locations:", GetLibCoreDexLocations()));
exec_argv.push_back("--image=" + core_art_location_);
exec_argv.push_back("--instruction-set=" + std::string(
GetInstructionSetString(kRuntimeISA)));
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index c964dbc..e31fe63 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -1037,13 +1037,20 @@
runtime->SetSentinel(heap->AllocNonMovableObject<true>(
self, java_lang_Object, java_lang_Object->GetObjectSize(), VoidFunctor()));
- for (gc::space::ImageSpace* image_space : spaces) {
+ const std::vector<std::string>& boot_class_path = runtime->GetBootClassPath();
+ if (boot_class_path.size() != spaces.size()) {
+ *error_msg = StringPrintf("Boot class path has %zu components but there are %zu image spaces.",
+ boot_class_path.size(),
+ spaces.size());
+ return false;
+ }
+ for (size_t i = 0u, size = spaces.size(); i != size; ++i) {
// Boot class loader, use a null handle.
std::vector<std::unique_ptr<const DexFile>> dex_files;
- if (!AddImageSpace(image_space,
+ if (!AddImageSpace(spaces[i],
ScopedNullHandle<mirror::ClassLoader>(),
- /*dex_elements=*/nullptr,
- /*dex_location=*/nullptr,
+ /*dex_elements=*/ nullptr,
+ /*dex_location=*/ boot_class_path[i].c_str(),
/*out*/&dex_files,
error_msg)) {
return false;
@@ -1981,13 +1988,7 @@
std::string dex_file_location(dex_cache->GetLocation()->ToModifiedUtf8());
// TODO: Only store qualified paths.
// If non qualified, qualify it.
- if (dex_file_location.find('/') == std::string::npos) {
- std::string dex_location_path = dex_location;
- const size_t pos = dex_location_path.find_last_of('/');
- CHECK_NE(pos, std::string::npos);
- dex_location_path = dex_location_path.substr(0, pos + 1); // Keep trailing '/'
- dex_file_location = dex_location_path + dex_file_location;
- }
+ dex_file_location = OatFile::ResolveRelativeEncodedDexLocation(dex_location, dex_file_location);
std::unique_ptr<const DexFile> dex_file = OpenOatDexFile(oat_file,
dex_file_location.c_str(),
error_msg);
diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc
index 86135c1..2f36d02 100644
--- a/runtime/gc/heap.cc
+++ b/runtime/gc/heap.cc
@@ -173,6 +173,8 @@
double foreground_heap_growth_multiplier,
size_t capacity,
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::string& image_file_name,
const InstructionSet image_instruction_set,
CollectorType foreground_collector_type,
@@ -350,7 +352,9 @@
// Load image space(s).
std::vector<std::unique_ptr<space::ImageSpace>> boot_image_spaces;
MemMap heap_reservation;
- if (space::ImageSpace::LoadBootImage(image_file_name,
+ if (space::ImageSpace::LoadBootImage(boot_class_path,
+ boot_class_path_locations,
+ image_file_name,
image_instruction_set,
heap_reservation_size,
&boot_image_spaces,
diff --git a/runtime/gc/heap.h b/runtime/gc/heap.h
index 411a446..8d81c11 100644
--- a/runtime/gc/heap.h
+++ b/runtime/gc/heap.h
@@ -174,7 +174,9 @@
double foreground_heap_growth_multiplier,
size_t capacity,
size_t non_moving_space_capacity,
- const std::string& original_image_file_name,
+ const std::vector<std::string>& boot_class_path,
+ const std::vector<std::string>& boot_class_path_locations,
+ const std::string& image_file_name,
InstructionSet image_instruction_set,
CollectorType foreground_collector_type,
CollectorType background_collector_type,
diff --git a/runtime/gc/space/image_space.cc b/runtime/gc/space/image_space.cc
index e494bd6..02ab50b 100644
--- a/runtime/gc/space/image_space.cc
+++ b/runtime/gc/space/image_space.cc
@@ -103,9 +103,8 @@
static bool GenerateImage(const std::string& image_filename,
InstructionSet image_isa,
std::string* error_msg) {
- const std::string boot_class_path_string(Runtime::Current()->GetBootClassPathString());
- std::vector<std::string> boot_class_path;
- Split(boot_class_path_string, ':', &boot_class_path);
+ Runtime* runtime = Runtime::Current();
+ const std::vector<std::string>& boot_class_path = runtime->GetBootClassPath();
if (boot_class_path.empty()) {
*error_msg = "Failed to generate image because no boot class path specified";
return false;
@@ -125,8 +124,11 @@
image_option_string += image_filename;
arg_vector.push_back(image_option_string);
- for (size_t i = 0; i < boot_class_path.size(); i++) {
+ const std::vector<std::string>& boot_class_path_locations = runtime->GetBootClassPathLocations();
+ DCHECK_EQ(boot_class_path.size(), boot_class_path_locations.size());
+ for (size_t i = 0u; i < boot_class_path.size(); i++) {
arg_vector.push_back(std::string("--dex-file=") + boot_class_path[i]);
+ arg_vector.push_back(std::string("--dex-location=") + boot_class_path_locations[i]);
}
std::string oat_file_option_string("--oat-file=");
@@ -1205,8 +1207,13 @@
class ImageSpace::BootImageLoader {
public:
- BootImageLoader(const std::string& image_location, InstructionSet image_isa)
- : image_location_(image_location),
+ BootImageLoader(const std::vector<std::string>& boot_class_path,
+ const std::vector<std::string>& boot_class_path_locations,
+ const std::string& image_location,
+ InstructionSet image_isa)
+ : boot_class_path_(boot_class_path),
+ boot_class_path_locations_(boot_class_path_locations),
+ image_location_(image_location),
image_isa_(image_isa),
is_zygote_(Runtime::Current()->IsZygote()),
has_system_(false),
@@ -1254,10 +1261,8 @@
/*out*/std::string* error_msg) REQUIRES_SHARED(Locks::mutator_lock_) {
TimingLogger logger(__PRETTY_FUNCTION__, /*precise=*/ true, VLOG_IS_ON(image));
std::string filename = GetSystemImageFilename(image_location_.c_str(), image_isa_);
- std::vector<std::string> locations;
- if (!GetBootClassPathImageLocations(image_location_, filename, &locations, error_msg)) {
- return false;
- }
+ std::vector<std::string> locations =
+ ExpandMultiImageLocations(boot_class_path_locations_, image_location_);
uint32_t image_start;
uint32_t image_end;
if (!GetBootImageAddressRange(filename, &image_start, &image_end, error_msg)) {
@@ -1290,9 +1295,16 @@
return false;
}
}
- for (std::unique_ptr<ImageSpace>& space : spaces) {
- static constexpr bool kValidateOatFile = false;
- if (!OpenOatFile(space.get(), kValidateOatFile, &logger, &image_reservation, error_msg)) {
+ for (size_t i = 0u, size = spaces.size(); i != size; ++i) {
+ std::string expected_boot_class_path =
+ (i == 0u) ? android::base::Join(boot_class_path_locations_, ':') : std::string();
+ if (!OpenOatFile(spaces[i].get(),
+ boot_class_path_[i],
+ expected_boot_class_path,
+ /*validate_oat_file=*/ false,
+ &logger,
+ &image_reservation,
+ error_msg)) {
return false;
}
}
@@ -1321,10 +1333,8 @@
/*out*/std::string* error_msg) REQUIRES_SHARED(Locks::mutator_lock_) {
TimingLogger logger(__PRETTY_FUNCTION__, /*precise=*/ true, VLOG_IS_ON(image));
DCHECK(DalvikCacheExists());
- std::vector<std::string> locations;
- if (!GetBootClassPathImageLocations(image_location_, cache_filename_, &locations, error_msg)) {
- return false;
- }
+ std::vector<std::string> locations =
+ ExpandMultiImageLocations(boot_class_path_locations_, image_location_);
uint32_t image_start;
uint32_t image_end;
if (!GetBootImageAddressRange(cache_filename_, &image_start, &image_end, error_msg)) {
@@ -1366,8 +1376,16 @@
return false;
}
}
- for (std::unique_ptr<ImageSpace>& space : spaces) {
- if (!OpenOatFile(space.get(), validate_oat_file, &logger, &image_reservation, error_msg)) {
+ for (size_t i = 0u, size = spaces.size(); i != size; ++i) {
+ std::string expected_boot_class_path =
+ (i == 0u) ? android::base::Join(boot_class_path_locations_, ':') : std::string();
+ if (!OpenOatFile(spaces[i].get(),
+ boot_class_path_[i],
+ expected_boot_class_path,
+ validate_oat_file,
+ &logger,
+ &image_reservation,
+ error_msg)) {
return false;
}
}
@@ -1887,8 +1905,6 @@
DCHECK(!spaces.empty());
ImageSpace* space = spaces[0].get();
const ImageHeader& image_header = space->GetImageHeader();
- // Use oat_file_non_owned_ from the `space` to set the runtime methods.
- runtime->SetInstructionSet(space->oat_file_non_owned_->GetOatHeader().GetInstructionSet());
runtime->SetResolutionMethod(image_header.GetImageMethod(ImageHeader::kResolutionMethod));
runtime->SetImtConflictMethod(image_header.GetImageMethod(ImageHeader::kImtConflictMethod));
runtime->SetImtUnimplementedMethod(
@@ -1952,6 +1968,8 @@
}
bool OpenOatFile(ImageSpace* space,
+ const std::string& dex_filename,
+ const std::string& expected_boot_class_path,
bool validate_oat_file,
TimingLogger* logger,
/*inout*/MemMap* image_reservation,
@@ -1967,13 +1985,15 @@
TimingLogger::ScopedTiming timing("OpenOatFile", logger);
std::string oat_filename =
ImageHeader::GetOatLocationFromImageLocation(space->GetImageFilename());
+ std::string oat_location =
+ ImageHeader::GetOatLocationFromImageLocation(space->GetImageLocation());
oat_file.reset(OatFile::Open(/*zip_fd=*/ -1,
oat_filename,
- oat_filename,
+ oat_location,
!Runtime::Current()->IsAotCompiler(),
/*low_4gb=*/ false,
- /*abs_dex_location=*/ nullptr,
+ /*abs_dex_location=*/ dex_filename.c_str(),
image_reservation,
error_msg));
if (oat_file == nullptr) {
@@ -1994,6 +2014,17 @@
space->GetName());
return false;
}
+ const char* oat_boot_class_path =
+ oat_file->GetOatHeader().GetStoreValueByKey(OatHeader::kBootClassPathKey);
+ oat_boot_class_path = (oat_boot_class_path != nullptr) ? oat_boot_class_path : "";
+ if (expected_boot_class_path != oat_boot_class_path) {
+ *error_msg = StringPrintf("Failed to match oat boot class path %s to expected "
+ "boot class path %s in image %s",
+ oat_boot_class_path,
+ expected_boot_class_path.c_str(),
+ space->GetName());
+ return false;
+ }
ptrdiff_t relocation_diff = space->Begin() - image_header.GetImageBegin();
CHECK(image_header.GetOatDataBegin() != nullptr);
uint8_t* oat_data_begin = image_header.GetOatDataBegin() + relocation_diff;
@@ -2019,37 +2050,6 @@
return true;
}
- // Extract boot class path from oat file associated with `image_filename`
- // and list all associated image locations.
- static bool GetBootClassPathImageLocations(const std::string& image_location,
- const std::string& image_filename,
- /*out*/ std::vector<std::string>* all_locations,
- /*out*/ std::string* error_msg) {
- std::string oat_filename = ImageHeader::GetOatLocationFromImageLocation(image_filename);
- std::unique_ptr<OatFile> oat_file(OatFile::Open(/*zip_fd=*/ -1,
- oat_filename,
- oat_filename,
- /*executable=*/ false,
- /*low_4gb=*/ false,
- /*abs_dex_location=*/ nullptr,
- /*reservation=*/ nullptr,
- error_msg));
- if (oat_file == nullptr) {
- *error_msg = StringPrintf("Failed to open oat file '%s' for image file %s: %s",
- oat_filename.c_str(),
- image_filename.c_str(),
- error_msg->c_str());
- return false;
- }
- const OatHeader& oat_header = oat_file->GetOatHeader();
- const char* boot_classpath = oat_header.GetStoreValueByKey(OatHeader::kBootClassPathKey);
- all_locations->push_back(image_location);
- if (boot_classpath != nullptr && boot_classpath[0] != 0) {
- ExtractMultiImageLocations(image_location, boot_classpath, all_locations);
- }
- return true;
- }
-
bool GetBootImageAddressRange(const std::string& filename,
/*out*/uint32_t* start,
/*out*/uint32_t* end,
@@ -2116,6 +2116,8 @@
return true;
}
+ const std::vector<std::string>& boot_class_path_;
+ const std::vector<std::string>& boot_class_path_locations_;
const std::string& image_location_;
InstructionSet image_isa_;
bool is_zygote_;
@@ -2163,6 +2165,8 @@
}
bool ImageSpace::LoadBootImage(
+ const std::vector<std::string>& boot_class_path,
+ const std::vector<std::string>& boot_class_path_locations,
const std::string& image_location,
const InstructionSet image_isa,
size_t extra_reservation_size,
@@ -2180,7 +2184,7 @@
return false;
}
- BootImageLoader loader(image_location, image_isa);
+ BootImageLoader loader(boot_class_path, boot_class_path_locations, image_location, image_isa);
// Step 0: Extra zygote work.
@@ -2341,57 +2345,6 @@
<< ",name=\"" << GetName() << "\"]";
}
-std::string ImageSpace::GetMultiImageBootClassPath(
- const std::vector<std::string>& dex_locations,
- const std::vector<std::string>& oat_filenames,
- const std::vector<std::string>& image_filenames) {
- DCHECK_GT(oat_filenames.size(), 1u);
- // If the image filename was adapted (e.g., for our tests), we need to change this here,
- // too, but need to strip all path components (they will be re-established when loading).
- // For example, dex location
- // /system/framework/core-libart.art
- // with image name
- // out/target/product/taimen/dex_bootjars/system/framework/arm64/boot-core-libart.art
- // yields boot class path component
- // /system/framework/boot-core-libart.art .
- std::ostringstream bootcp_oss;
- bool first_bootcp = true;
- for (size_t i = 0; i < dex_locations.size(); ++i) {
- if (!first_bootcp) {
- bootcp_oss << ":";
- }
-
- std::string dex_loc = dex_locations[i];
- std::string image_filename = image_filenames[i];
-
- // Use the dex_loc path, but the image_filename name (without path elements).
- size_t dex_last_slash = dex_loc.rfind('/');
-
- // npos is max(size_t). That makes this a bit ugly.
- size_t image_last_slash = image_filename.rfind('/');
- size_t image_last_at = image_filename.rfind('@');
- size_t image_last_sep = (image_last_slash == std::string::npos)
- ? image_last_at
- : (image_last_at == std::string::npos)
- ? image_last_slash
- : std::max(image_last_slash, image_last_at);
- // Note: whenever image_last_sep == npos, +1 overflow means using the full string.
-
- if (dex_last_slash == std::string::npos) {
- dex_loc = image_filename.substr(image_last_sep + 1);
- } else {
- dex_loc = dex_loc.substr(0, dex_last_slash + 1) +
- image_filename.substr(image_last_sep + 1);
- }
-
- // Image filenames already end with .art, no need to replace.
-
- bootcp_oss << dex_loc;
- first_bootcp = false;
- }
- return bootcp_oss.str();
-}
-
bool ImageSpace::ValidateOatFile(const OatFile& oat_file, std::string* error_msg) {
const ArtDexFileLoader dex_file_loader;
for (const OatDexFile* oat_dex_file : oat_file.GetOatDexFiles()) {
@@ -2452,46 +2405,55 @@
return true;
}
-void ImageSpace::ExtractMultiImageLocations(const std::string& input_image_file_name,
- const std::string& boot_classpath,
- std::vector<std::string>* image_file_names) {
- DCHECK(image_file_names != nullptr);
+std::vector<std::string> ImageSpace::ExpandMultiImageLocations(
+ const std::vector<std::string>& dex_locations,
+ const std::string& image_location) {
+ DCHECK(!dex_locations.empty());
- std::vector<std::string> images;
- Split(boot_classpath, ':', &images);
+ // Find the path.
+ size_t last_slash = image_location.rfind('/');
+ CHECK_NE(last_slash, std::string::npos);
- // Add the rest into the list. We have to adjust locations, possibly:
- //
- // For example, image_file_name is /a/b/c/d/e.art
- // images[0] is f/c/d/e.art
- // ----------------------------------------------
- // images[1] is g/h/i/j.art -> /a/b/h/i/j.art
- const std::string& first_image = images[0];
- // Length of common suffix.
- size_t common = 0;
- while (common < input_image_file_name.size() &&
- common < first_image.size() &&
- *(input_image_file_name.end() - common - 1) == *(first_image.end() - common - 1)) {
- ++common;
+ // We also need to honor path components that were encoded through '@'. Otherwise the loading
+ // code won't be able to find the images.
+ if (image_location.find('@', last_slash) != std::string::npos) {
+ last_slash = image_location.rfind('@');
}
- // We want to replace the prefix of the input image with the prefix of the boot class path.
- // This handles the case where the image file contains @ separators.
- // Example image_file_name is oats/system@framework@boot.art
- // images[0] is .../arm/boot.art
- // means that the image name prefix will be oats/system@framework@
- // so that the other images are openable.
- const size_t old_prefix_length = first_image.size() - common;
- const std::string new_prefix = input_image_file_name.substr(
- 0,
- input_image_file_name.size() - common);
- // Apply pattern to images[1] .. images[n].
- for (size_t i = 1; i < images.size(); ++i) {
- const std::string& image = images[i];
- CHECK_GT(image.length(), old_prefix_length);
- std::string suffix = image.substr(old_prefix_length);
- image_file_names->push_back(new_prefix + suffix);
+ // Find the dot separating the primary image name from the extension.
+ size_t last_dot = image_location.rfind('.');
+ // Extract the extension and base (the path and primary image name).
+ std::string extension;
+ std::string base = image_location;
+ if (last_dot != std::string::npos && last_dot > last_slash) {
+ extension = image_location.substr(last_dot); // Including the dot.
+ base.resize(last_dot);
}
+ // For non-empty primary image name, add '-' to the `base`.
+ if (last_slash + 1u != base.size()) {
+ base += '-';
+ }
+
+ std::vector<std::string> locations;
+ locations.reserve(dex_locations.size());
+ locations.push_back(image_location);
+
+ // Now create the other names. Use a counted loop to skip the first one.
+ for (size_t i = 1u; i < dex_locations.size(); ++i) {
+ // Replace path with `base` (i.e. image path and prefix) and replace the original
+ // extension (if any) with `extension`.
+ std::string name = dex_locations[i];
+ size_t last_dex_slash = name.rfind('/');
+ if (last_dex_slash != std::string::npos) {
+ name = name.substr(last_dex_slash + 1);
+ }
+ size_t last_dex_dot = name.rfind('.');
+ if (last_dex_dot != std::string::npos) {
+ name.resize(last_dex_dot);
+ }
+ locations.push_back(base + name + extension);
+ }
+ return locations;
}
void ImageSpace::DumpSections(std::ostream& os) const {
diff --git a/runtime/gc/space/image_space.h b/runtime/gc/space/image_space.h
index aa45ed3..05e7fa5 100644
--- a/runtime/gc/space/image_space.h
+++ b/runtime/gc/space/image_space.h
@@ -39,9 +39,11 @@
// Load boot image spaces from a primary image file for a specified instruction set.
//
// On successful return, the loaded spaces are added to boot_image_spaces (which must be
- // empty on entry) and oat_file_end is updated with the (page-aligned) end of the last
- // oat file.
+ // empty on entry) and `extra_reservation` is set to the requested reservation located
+ // after the end of the last loaded oat file.
static bool LoadBootImage(
+ const std::vector<std::string>& boot_class_path,
+ const std::vector<std::string>& boot_class_path_locations,
const std::string& image_location,
const InstructionSet image_isa,
size_t extra_reservation_size,
@@ -122,15 +124,10 @@
bool* has_data,
bool *is_global_cache);
- // Use the input image filename to adapt the names in the given boot classpath to establish
- // complete locations for secondary images.
- static void ExtractMultiImageLocations(const std::string& input_image_file_name,
- const std::string& boot_classpath,
- std::vector<std::string>* image_filenames);
-
- static std::string GetMultiImageBootClassPath(const std::vector<std::string>& dex_locations,
- const std::vector<std::string>& oat_filenames,
- const std::vector<std::string>& image_filenames);
+ // Expand a single image location to multi-image locations based on the dex locations.
+ static std::vector<std::string> ExpandMultiImageLocations(
+ const std::vector<std::string>& dex_locations,
+ const std::string& image_location);
// Returns true if the dex checksums in the given oat file match the
// checksums of the original dex files on disk. This is intended to be used
diff --git a/runtime/interpreter/unstarted_runtime.cc b/runtime/interpreter/unstarted_runtime.cc
index e292a76..4fa7271 100644
--- a/runtime/interpreter/unstarted_runtime.cc
+++ b/runtime/interpreter/unstarted_runtime.cc
@@ -571,12 +571,9 @@
Runtime* runtime = Runtime::Current();
- std::vector<std::string> split;
- Split(runtime->GetBootClassPathString(), ':', &split);
- if (split.empty()) {
- AbortTransactionOrFail(self,
- "Boot classpath not set or split error:: %s",
- runtime->GetBootClassPathString().c_str());
+ const std::vector<std::string>& boot_class_path = Runtime::Current()->GetBootClassPath();
+ if (boot_class_path.empty()) {
+ AbortTransactionOrFail(self, "Boot classpath not set");
return;
}
@@ -584,7 +581,7 @@
size_t map_size;
std::string last_error_msg; // Only store the last message (we could concatenate).
- for (const std::string& jar_file : split) {
+ for (const std::string& jar_file : boot_class_path) {
mem_map = FindAndExtractEntry(jar_file, resource_cstr, &map_size, &last_error_msg);
if (mem_map.IsValid()) {
break;
diff --git a/runtime/jdwp/jdwp_handler.cc b/runtime/jdwp/jdwp_handler.cc
index d31f166..37365ff 100644
--- a/runtime/jdwp/jdwp_handler.cc
+++ b/runtime/jdwp/jdwp_handler.cc
@@ -292,8 +292,7 @@
expandBufAddUtf8String(pReply, str);
}
- std::vector<std::string> boot_class_path;
- Split(Runtime::Current()->GetBootClassPathString(), ':', &boot_class_path);
+ std::vector<std::string> boot_class_path = Runtime::Current()->GetBootClassPath();
expandBufAdd4BE(pReply, boot_class_path.size());
for (const std::string& str : boot_class_path) {
expandBufAddUtf8String(pReply, str);
diff --git a/runtime/native/dalvik_system_VMRuntime.cc b/runtime/native/dalvik_system_VMRuntime.cc
index e213dc7..3e5003c 100644
--- a/runtime/native/dalvik_system_VMRuntime.cc
+++ b/runtime/native/dalvik_system_VMRuntime.cc
@@ -24,7 +24,8 @@
#include <limits.h>
#include "nativehelper/scoped_utf_chars.h"
-#include "android-base/stringprintf.h"
+#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
#include "arch/instruction_set.h"
#include "art_method-inl.h"
@@ -222,7 +223,8 @@
}
static jstring VMRuntime_bootClassPath(JNIEnv* env, jobject) {
- return env->NewStringUTF(DefaultToDot(Runtime::Current()->GetBootClassPathString()));
+ std::string boot_class_path = android::base::Join(Runtime::Current()->GetBootClassPath(), ':');
+ return env->NewStringUTF(DefaultToDot(boot_class_path));
}
static jstring VMRuntime_classPath(JNIEnv* env, jobject) {
diff --git a/runtime/oat.h b/runtime/oat.h
index ee46f42..b09c81e 100644
--- a/runtime/oat.h
+++ b/runtime/oat.h
@@ -31,8 +31,8 @@
class PACKED(4) OatHeader {
public:
static constexpr uint8_t kOatMagic[] = { 'o', 'a', 't', '\n' };
- // Last oat version changed reason: Image checksums.
- static constexpr uint8_t kOatVersion[] = { '1', '6', '4', '\0' };
+ // Last oat version changed reason: Pass boot class path to LoadBootImage.
+ static constexpr uint8_t kOatVersion[] = { '1', '6', '5', '\0' };
static constexpr const char* kDex2OatCmdLineKey = "dex2oat-cmdline";
static constexpr const char* kDebuggableKey = "debuggable";
diff --git a/runtime/parsed_options.cc b/runtime/parsed_options.cc
index 29b5690..17ff3a2 100644
--- a/runtime/parsed_options.cc
+++ b/runtime/parsed_options.cc
@@ -20,6 +20,7 @@
#include <sstream>
#include <android-base/logging.h>
+#include <android-base/strings.h>
#include "base/file_utils.h"
#include "base/macros.h"
@@ -78,7 +79,7 @@
.Define("-showversion")
.IntoKey(M::ShowVersion)
.Define("-Xbootclasspath:_")
- .WithType<std::string>()
+ .WithType<ParseStringList<':'>>() // std::vector<std::string>, split by :
.IntoKey(M::BootClassPath)
.Define("-Xbootclasspath-locations:_")
.WithType<ParseStringList<':'>>() // std::vector<std::string>, split by :
@@ -513,7 +514,7 @@
GetInstructionSetString(kRuntimeISA));
Exit(0);
} else if (args.Exists(M::BootClassPath)) {
- LOG(INFO) << "setting boot class path to " << *args.Get(M::BootClassPath);
+ LOG(INFO) << "setting boot class path to " << args.Get(M::BootClassPath)->Join();
}
if (args.GetOrDefault(M::Interpret)) {
@@ -525,8 +526,9 @@
}
// Set a default boot class path if we didn't get an explicit one via command line.
- if (getenv("BOOTCLASSPATH") != nullptr) {
- args.SetIfMissing(M::BootClassPath, std::string(getenv("BOOTCLASSPATH")));
+ const char* env_bcp = getenv("BOOTCLASSPATH");
+ if (env_bcp != nullptr) {
+ args.SetIfMissing(M::BootClassPath, ParseStringList<':'>::Split(env_bcp));
}
// Set a default class path if we didn't get an explicit one via command line.
@@ -586,22 +588,20 @@
args.Set(M::BackgroundGc, BackgroundGcOption { background_collector_type_ });
}
- auto boot_class_path_string = args.GetOrDefault(M::BootClassPath);
- {
- auto&& boot_class_path = args.GetOrDefault(M::BootClassPath);
- auto&& boot_class_path_locations = args.GetOrDefault(M::BootClassPathLocations);
- if (args.Exists(M::BootClassPathLocations)) {
- size_t boot_class_path_count = ParseStringList<':'>::Split(boot_class_path).Size();
-
- if (boot_class_path_count != boot_class_path_locations.Size()) {
- Usage("The number of boot class path files does not match"
- " the number of boot class path locations given\n"
- " boot class path files (%zu): %s\n"
- " boot class path locations (%zu): %s\n",
- boot_class_path.size(), boot_class_path_string.c_str(),
- boot_class_path_locations.Size(), boot_class_path_locations.Join().c_str());
- return false;
- }
+ const ParseStringList<':'>* boot_class_path_locations = args.Get(M::BootClassPathLocations);
+ if (boot_class_path_locations != nullptr && boot_class_path_locations->Size() != 0u) {
+ const ParseStringList<':'>* boot_class_path = args.Get(M::BootClassPath);
+ if (boot_class_path == nullptr ||
+ boot_class_path_locations->Size() != boot_class_path->Size()) {
+ Usage("The number of boot class path files does not match"
+ " the number of boot class path locations given\n"
+ " boot class path files (%zu): %s\n"
+ " boot class path locations (%zu): %s\n",
+ (boot_class_path != nullptr) ? boot_class_path->Size() : 0u,
+ (boot_class_path != nullptr) ? boot_class_path->Join().c_str() : "<nil>",
+ boot_class_path_locations->Size(),
+ boot_class_path_locations->Join().c_str());
+ return false;
}
}
diff --git a/runtime/parsed_options_test.cc b/runtime/parsed_options_test.cc
index 705cc6c..cbb7b82 100644
--- a/runtime/parsed_options_test.cc
+++ b/runtime/parsed_options_test.cc
@@ -40,8 +40,7 @@
boot_class_path += "-Xbootclasspath:";
bool first_dex_file = true;
- for (const std::string &dex_file_name :
- CommonRuntimeTest::GetLibCoreDexFileNames()) {
+ for (const std::string &dex_file_name : CommonRuntimeTest::GetLibCoreDexFileNames()) {
if (!first_dex_file) {
class_path += ":";
} else {
@@ -50,6 +49,8 @@
class_path += dex_file_name;
}
boot_class_path += class_path;
+ std::vector<std::string> expected_boot_class_path;
+ Split(class_path, ':', &expected_boot_class_path);
RuntimeOptions options;
options.push_back(std::make_pair(boot_class_path.c_str(), nullptr));
@@ -78,9 +79,11 @@
using Opt = RuntimeArgumentMap;
#define EXPECT_PARSED_EQ(expected, actual_key) EXPECT_EQ(expected, map.GetOrDefault(actual_key))
+#define EXPECT_PARSED_EQ_AS_STRING_VECTOR(expected, actual_key) \
+ EXPECT_EQ(expected, static_cast<std::vector<std::string>>(map.GetOrDefault(actual_key)))
#define EXPECT_PARSED_EXISTS(actual_key) EXPECT_TRUE(map.Exists(actual_key))
- EXPECT_PARSED_EQ(class_path, Opt::BootClassPath);
+ EXPECT_PARSED_EQ_AS_STRING_VECTOR(expected_boot_class_path, Opt::BootClassPath);
EXPECT_PARSED_EQ(class_path, Opt::ClassPath);
EXPECT_PARSED_EQ(std::string("boot_image"), Opt::Image);
EXPECT_PARSED_EXISTS(Opt::CheckJni);
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index 182319a..44e01c2 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -1097,7 +1097,45 @@
Monitor::Init(runtime_options.GetOrDefault(Opt::LockProfThreshold),
runtime_options.GetOrDefault(Opt::StackDumpLockProfThreshold));
- boot_class_path_string_ = runtime_options.ReleaseOrDefault(Opt::BootClassPath);
+ image_location_ = runtime_options.GetOrDefault(Opt::Image);
+ SetInstructionSet(runtime_options.GetOrDefault(Opt::ImageInstructionSet));
+ boot_class_path_ = runtime_options.ReleaseOrDefault(Opt::BootClassPath);
+ boot_class_path_locations_ = runtime_options.ReleaseOrDefault(Opt::BootClassPathLocations);
+ DCHECK(boot_class_path_locations_.empty() ||
+ boot_class_path_locations_.size() == boot_class_path_.size());
+ if (boot_class_path_.empty()) {
+ // Try to extract the boot class path from the system boot image.
+ if (image_location_.empty()) {
+ LOG(ERROR) << "Empty boot class path, cannot continue without image.";
+ return false;
+ }
+ std::string system_oat_filename = ImageHeader::GetOatLocationFromImageLocation(
+ GetSystemImageFilename(image_location_.c_str(), instruction_set_));
+ std::string system_oat_location = ImageHeader::GetOatLocationFromImageLocation(image_location_);
+ std::string error_msg;
+ std::unique_ptr<OatFile> oat_file(OatFile::Open(/*zip_fd=*/ -1,
+ system_oat_filename,
+ system_oat_location,
+ /*executable=*/ false,
+ /*low_4gb=*/ false,
+ /*abs_dex_location=*/ nullptr,
+ /*reservation=*/ nullptr,
+ &error_msg));
+ if (oat_file == nullptr) {
+ LOG(ERROR) << "Could not open boot oat file for extracting boot class path: " << error_msg;
+ return false;
+ }
+ const OatHeader& oat_header = oat_file->GetOatHeader();
+ const char* oat_boot_class_path = oat_header.GetStoreValueByKey(OatHeader::kBootClassPathKey);
+ if (oat_boot_class_path != nullptr) {
+ Split(oat_boot_class_path, ':', &boot_class_path_);
+ }
+ if (boot_class_path_.empty()) {
+ LOG(ERROR) << "Boot class path missing from boot image oat file " << oat_file->GetLocation();
+ return false;
+ }
+ }
+
class_path_string_ = runtime_options.ReleaseOrDefault(Opt::ClassPath);
properties_ = runtime_options.ReleaseOrDefault(Opt::PropertiesList);
@@ -1123,7 +1161,6 @@
}
}
image_compiler_options_ = runtime_options.ReleaseOrDefault(Opt::ImageCompilerOptions);
- image_location_ = runtime_options.GetOrDefault(Opt::Image);
max_spins_before_thin_lock_inflation_ =
runtime_options.GetOrDefault(Opt::MaxSpinsBeforeThinLockInflation);
@@ -1192,8 +1229,10 @@
foreground_heap_growth_multiplier,
runtime_options.GetOrDefault(Opt::MemoryMaximumSize),
runtime_options.GetOrDefault(Opt::NonMovingSpaceCapacity),
- runtime_options.GetOrDefault(Opt::Image),
- runtime_options.GetOrDefault(Opt::ImageInstructionSet),
+ GetBootClassPath(),
+ GetBootClassPathLocations(),
+ image_location_,
+ instruction_set_,
// Override the collector type to CC if the read barrier config.
kUseReadBarrier ? gc::kCollectorTypeCC : xgc_option.collector_type_,
kUseReadBarrier ? BackgroundGcOption(gc::kCollectorTypeCCBackground)
@@ -1393,16 +1432,6 @@
image_space->VerifyImageAllocations();
}
}
- if (boot_class_path_string_.empty()) {
- // The bootclasspath is not explicitly specified: construct it from the loaded dex files.
- const std::vector<const DexFile*>& boot_class_path = GetClassLinker()->GetBootClassPath();
- std::vector<std::string> dex_locations;
- dex_locations.reserve(boot_class_path.size());
- for (const DexFile* dex_file : boot_class_path) {
- dex_locations.push_back(dex_file->GetLocation());
- }
- boot_class_path_string_ = android::base::Join(dex_locations, ':');
- }
{
ScopedTrace trace2("AddImageStringsToTable");
for (gc::space::ImageSpace* image_space : heap_->GetBootImageSpaces()) {
@@ -1415,24 +1444,12 @@
DeoptimizeBootImage();
}
} else {
- std::vector<std::string> dex_filenames;
- Split(boot_class_path_string_, ':', &dex_filenames);
-
- std::vector<std::string> dex_locations;
- if (!runtime_options.Exists(Opt::BootClassPathLocations)) {
- dex_locations = dex_filenames;
- } else {
- dex_locations = runtime_options.GetOrDefault(Opt::BootClassPathLocations);
- CHECK_EQ(dex_filenames.size(), dex_locations.size());
- }
-
std::vector<std::unique_ptr<const DexFile>> boot_class_path;
if (runtime_options.Exists(Opt::BootClassPathDexList)) {
boot_class_path.swap(*runtime_options.GetOrDefault(Opt::BootClassPathDexList));
} else {
- OpenDexFiles(dex_filenames, dex_locations, &boot_class_path);
+ OpenDexFiles(GetBootClassPath(), GetBootClassPathLocations(), &boot_class_path);
}
- instruction_set_ = runtime_options.GetOrDefault(Opt::ImageInstructionSet);
if (!class_linker_->InitWithoutImage(std::move(boot_class_path), &error_msg)) {
LOG(ERROR) << "Could not initialize without image: " << error_msg;
return false;
diff --git a/runtime/runtime.h b/runtime/runtime.h
index 4533376..b76a658 100644
--- a/runtime/runtime.h
+++ b/runtime/runtime.h
@@ -243,8 +243,14 @@
~Runtime();
- const std::string& GetBootClassPathString() const {
- return boot_class_path_string_;
+ const std::vector<std::string>& GetBootClassPath() const {
+ return boot_class_path_;
+ }
+
+ const std::vector<std::string>& GetBootClassPathLocations() const {
+ DCHECK(boot_class_path_locations_.empty() ||
+ boot_class_path_locations_.size() == boot_class_path_.size());
+ return boot_class_path_locations_.empty() ? boot_class_path_ : boot_class_path_locations_;
}
const std::string& GetClassPathString() const {
@@ -866,7 +872,8 @@
std::vector<std::string> image_compiler_options_;
std::string image_location_;
- std::string boot_class_path_string_;
+ std::vector<std::string> boot_class_path_;
+ std::vector<std::string> boot_class_path_locations_;
std::string class_path_string_;
std::vector<std::string> properties_;
diff --git a/runtime/runtime_options.def b/runtime/runtime_options.def
index 5cec309..2b2919e 100644
--- a/runtime/runtime_options.def
+++ b/runtime/runtime_options.def
@@ -37,7 +37,7 @@
RUNTIME_OPTIONS_KEY (Unit, Zygote)
RUNTIME_OPTIONS_KEY (Unit, Help)
RUNTIME_OPTIONS_KEY (Unit, ShowVersion)
-RUNTIME_OPTIONS_KEY (std::string, BootClassPath)
+RUNTIME_OPTIONS_KEY (ParseStringList<':'>,BootClassPath) // std::vector<std::string>
RUNTIME_OPTIONS_KEY (ParseStringList<':'>,BootClassPathLocations) // std::vector<std::string>
RUNTIME_OPTIONS_KEY (std::string, ClassPath)
RUNTIME_OPTIONS_KEY (std::string, Image)
diff --git a/tools/run-jdwp-tests.sh b/tools/run-jdwp-tests.sh
index 20e5c64..f4a2dc1 100755
--- a/tools/run-jdwp-tests.sh
+++ b/tools/run-jdwp-tests.sh
@@ -43,6 +43,22 @@
java_lib_location="${ANDROID_HOST_OUT}/../common/obj/JAVA_LIBRARIES"
make_target_name="apache-harmony-jdwp-tests-hostdex"
+function boot_classpath_arg {
+ local dir="$1"
+ local suffix="$2"
+ shift 2
+ local separator=""
+ for var
+ do
+ printf -- "${separator}${dir}/${var}${suffix}.jar";
+ separator=":"
+ done
+}
+
+# Note: This must match the TEST_CORE_JARS in Android.common_path.mk
+# because that's what we use for compiling the core.art image.
+BOOT_CLASSPATH_JARS="core-oj core-libart core-simple conscrypt okhttp bouncycastle"
+
vm_args=""
art="$android_root/bin/art"
art_debugee="sh $android_root/bin/art"
@@ -59,6 +75,8 @@
explicit_debug="no"
verbose="no"
image="-Ximage:/data/art-test/core.art"
+boot_classpath="$(boot_classpath_arg /system/framework -testdex $BOOT_CLASSPATH_JARS)"
+boot_classpath_locations=""
with_jdwp_path=""
agent_wrapper=""
vm_args=""
@@ -90,6 +108,17 @@
art_debugee="bash ${OUT_DIR-out}/host/linux-x86/bin/art"
# We force generation of a new image to avoid build-time and run-time classpath differences.
image="-Ximage:/system/non/existent/vogar.art"
+ # Pass the host boot classpath.
+ if [ "${ANDROID_HOST_OUT:0:${#ANDROID_BUILD_TOP}+1}" = "${ANDROID_BUILD_TOP}/" ]; then
+ framework_location="${ANDROID_HOST_OUT:${#ANDROID_BUILD_TOP}+1}/framework"
+ else
+ echo "error: ANDROID_BUILD_TOP/ is not a prefix of ANDROID_HOST_OUT"
+ echo "ANDROID_BUILD_TOP=${ANDROID_BUILD_TOP}"
+ echo "ANDROID_HOST_OUT=${ANDROID_HOST_OUT}"
+ exit
+ fi
+ boot_classpath="$(boot_classpath_arg ${ANDROID_HOST_OUT}/framework -hostdex $BOOT_CLASSPATH_JARS)"
+ boot_classpath_locations="$(boot_classpath_arg ${framework_location} -hostdex $BOOT_CLASSPATH_JARS)"
# We do not need a device directory on host.
device_dir=""
# Vogar knows which VM to use on host.
@@ -104,6 +133,8 @@
debuggee_args=""
# No image. On the RI.
image=""
+ boot_classpath=""
+ boot_classpath_locations=""
# We do not need a device directory on RI.
device_dir=""
# Vogar knows which VM to use on RI.
@@ -305,6 +336,15 @@
if [[ "$image" != "" ]]; then
vm_args="$vm_args --vm-arg $image"
+ debuggee_args="$debuggee_args $image"
+fi
+if [[ "$boot_classpath" != "" ]]; then
+ vm_args="$vm_args --vm-arg -Xbootclasspath:${boot_classpath}"
+ debuggee_args="$debuggee_args -Xbootclasspath:${boot_classpath}"
+fi
+if [[ "$boot_classpath_locations" != "" ]]; then
+ vm_args="$vm_args --vm-arg -Xbootclasspath-locations:${boot_classpath_locations}"
+ debuggee_args="$debuggee_args -Xbootclasspath-locations:${boot_classpath_locations}"
fi
if [[ "$plugin" != "" ]]; then
@@ -363,7 +403,7 @@
--vm-arg -Djpda.settings.waitingTime=$jdwp_test_timeout \
--vm-arg -Djpda.settings.transportAddress=127.0.0.1:55107 \
--vm-arg -Djpda.settings.dumpProcess="$dump_command" \
- --vm-arg -Djpda.settings.debuggeeJavaPath="$art_debugee $plugin $image $debuggee_args" \
+ --vm-arg -Djpda.settings.debuggeeJavaPath="$art_debugee $plugin $debuggee_args" \
--classpath "$test_jar" \
$toolchain_args \
$test
diff --git a/tools/run-libcore-tests.sh b/tools/run-libcore-tests.sh
index 2d39b2a..63f1fce 100755
--- a/tools/run-libcore-tests.sh
+++ b/tools/run-libcore-tests.sh
@@ -46,6 +46,21 @@
done
}
+function boot_classpath_arg {
+ local dir="$1"
+ local suffix="$2"
+ shift 2
+ printf -- "--vm-arg -Xbootclasspath"
+ for var
+ do
+ printf -- ":${dir}/${var}${suffix}.jar";
+ done
+}
+
+# Note: This must match the TEST_CORE_JARS in Android.common_path.mk
+# because that's what we use for compiling the core.art image.
+BOOT_CLASSPATH_JARS="core-oj core-libart core-simple conscrypt okhttp bouncycastle"
+
DEPS="core-tests jsr166-tests mockito-target"
for lib in $DEPS
@@ -110,6 +125,7 @@
if [[ "$1" == "--mode=device" ]]; then
device_mode=true
vogar_args="$vogar_args --vm-arg -Ximage:/data/art-test/core.art"
+ vogar_args="$vogar_args $(boot_classpath_arg /system/framework -testdex $BOOT_CLASSPATH_JARS)"
shift
elif [[ "$1" == "--mode=host" ]]; then
# We explicitly give a wrong path for the image, to ensure vogar