diff options
author | 2018-12-07 18:04:10 +0000 | |
---|---|---|
committer | 2018-12-07 18:13:55 +0000 | |
commit | 91f1032505cfaec3aef51fc0a3085b213813f0ed (patch) | |
tree | 6469e772d9fb562d26dc1d22dd0b71844bbb743f | |
parent | 573b3877fac3c5a4a9703301502694fe7219b21c (diff) |
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
-rw-r--r-- | cmdline/cmdline_parser_test.cc | 15 | ||||
-rw-r--r-- | dex2oat/dex2oat.cc | 98 | ||||
-rw-r--r-- | dex2oat/linker/image_test.h | 14 | ||||
-rw-r--r-- | oatdump/oatdump_test.h | 5 | ||||
-rw-r--r-- | runtime/class_linker.cc | 23 | ||||
-rw-r--r-- | runtime/gc/heap.cc | 6 | ||||
-rw-r--r-- | runtime/gc/heap.h | 4 | ||||
-rw-r--r-- | runtime/gc/space/image_space.cc | 246 | ||||
-rw-r--r-- | runtime/gc/space/image_space.h | 19 | ||||
-rw-r--r-- | runtime/interpreter/unstarted_runtime.cc | 11 | ||||
-rw-r--r-- | runtime/jdwp/jdwp_handler.cc | 3 | ||||
-rw-r--r-- | runtime/native/dalvik_system_VMRuntime.cc | 6 | ||||
-rw-r--r-- | runtime/oat.h | 4 | ||||
-rw-r--r-- | runtime/parsed_options.cc | 40 | ||||
-rw-r--r-- | runtime/parsed_options_test.cc | 9 | ||||
-rw-r--r-- | runtime/runtime.cc | 71 | ||||
-rw-r--r-- | runtime/runtime.h | 13 | ||||
-rw-r--r-- | runtime/runtime_options.def | 2 | ||||
-rwxr-xr-x | tools/run-jdwp-tests.sh | 42 | ||||
-rwxr-xr-x | tools/run-libcore-tests.sh | 16 |
20 files changed, 319 insertions, 328 deletions
diff --git a/cmdline/cmdline_parser_test.cc b/cmdline/cmdline_parser_test.cc index 97daafadd8..101e5c42cd 100644 --- a/cmdline/cmdline_parser_test.cc +++ b/cmdline/cmdline_parser_test.cc @@ -63,6 +63,12 @@ namespace art { 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 @@ TEST_F(CmdlineParserTest, TestSimpleSuccesses) { } 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 f7299344f2..a5bba9bb97 100644 --- a/dex2oat/dex2oat.cc +++ b/dex2oat/dex2oat.cc @@ -103,6 +103,7 @@ namespace art { 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,91 +965,24 @@ class Dex2Oat final { } 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()); - } - // 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); - - 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()); - } - // 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('@'); + if (image_filenames_[0].rfind('/') == std::string::npos) { + Usage("Unusable boot image filename %s", image_filenames_[0].c_str()); } + image_filenames_ = ImageSpace::ExpandMultiImageLocations(dex_locations_, image_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 (oat_filenames_[0].rfind('/') == std::string::npos) { + Usage("Unusable boot image oat filename %s", oat_filenames_[0].c_str()); } - if (!prefix.empty()) { - prefix = prefix + "-"; - } - - base_img = base_img.substr(0, last_img_slash + 1); + oat_filenames_ = ImageSpace::ExpandMultiImageLocations(dex_locations_, oat_filenames_[0]); - 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()); - } - base_symbol_oat = base_symbol_oat.substr(0, last_symbol_oat_slash + 1); - } - - // 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()); + if (oat_unstripped_[0].rfind('/') == std::string::npos) { + Usage("Unusable boot image symbol filename %s", oat_unstripped_[0].c_str()); } + oat_unstripped_ = ImageSpace::ExpandMultiImageLocations(dex_locations_, oat_unstripped_[0]); } } - // 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) { if (!avoid_storing_invocation_) { std::ostringstream oss; @@ -1497,11 +1431,8 @@ class Dex2Oat final { 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 @@ class Dex2Oat final { 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 @@ class Dex2Oat final { 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 13fa0f033b..bd8cf5ad56 100644 --- a/dex2oat/linker/image_test.h +++ b/dex2oat/linker/image_test.h @@ -169,10 +169,11 @@ inline void ImageTest::DoCompile(ImageHeader::StorageMode storage_mode, { // 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 @@ inline void ImageTest::DoCompile(ImageHeader::StorageMode storage_mode, 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 728939f93c..dfa659b7e9 100644 --- a/oatdump/oatdump_test.h +++ b/oatdump/oatdump_test.h @@ -178,6 +178,11 @@ class OatDumpTest : public CommonRuntimeTest { 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 c964dbcf59..e31fe6315b 100644 --- a/runtime/class_linker.cc +++ b/runtime/class_linker.cc @@ -1037,13 +1037,20 @@ bool ClassLinker::InitFromBootImage(std::string* error_msg) { 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 @@ bool ClassLinker::AddImageSpace( 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 86135c1bc2..2f36d02eef 100644 --- a/runtime/gc/heap.cc +++ b/runtime/gc/heap.cc @@ -173,6 +173,8 @@ Heap::Heap(size_t initial_size, 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 @@ Heap::Heap(size_t initial_size, // 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 411a4469d9..8d81c11a43 100644 --- a/runtime/gc/heap.h +++ b/runtime/gc/heap.h @@ -174,7 +174,9 @@ class Heap { 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 e494bd681d..02ab50bded 100644 --- a/runtime/gc/space/image_space.cc +++ b/runtime/gc/space/image_space.cc @@ -103,9 +103,8 @@ static int32_t ChooseRelocationOffsetDelta() { 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 @@ static bool GenerateImage(const std::string& image_filename, 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::Loader { 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 @@ class ImageSpace::BootImageLoader { /*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 @@ class ImageSpace::BootImageLoader { 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 @@ class ImageSpace::BootImageLoader { /*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 @@ class ImageSpace::BootImageLoader { 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 @@ class ImageSpace::BootImageLoader { 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 @@ class ImageSpace::BootImageLoader { } 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 @@ class ImageSpace::BootImageLoader { 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 @@ class ImageSpace::BootImageLoader { 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 @@ class ImageSpace::BootImageLoader { 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 @@ class ImageSpace::BootImageLoader { 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 @@ static bool CheckSpace(const std::string& cache_filename, std::string* error_msg } 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 @@ bool ImageSpace::LoadBootImage( 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 @@ void ImageSpace::Dump(std::ostream& os) const { << ",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 @@ bool ImageSpace::ValidateOatFile(const OatFile& oat_file, std::string* error_msg 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()); + + // Find the path. + size_t last_slash = image_location.rfind('/'); + CHECK_NE(last_slash, std::string::npos); - std::vector<std::string> images; - Split(boot_classpath, ':', &images); + // 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('@'); + } - // 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; + // 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 += '-'; } - // 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); + + 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 aa45ed3952..05e7fa5cca 100644 --- a/runtime/gc/space/image_space.h +++ b/runtime/gc/space/image_space.h @@ -39,9 +39,11 @@ class ImageSpace : public MemMapSpace { // 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 @@ class ImageSpace : public MemMapSpace { 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 e292a7612c..4fa7271ff4 100644 --- a/runtime/interpreter/unstarted_runtime.cc +++ b/runtime/interpreter/unstarted_runtime.cc @@ -571,12 +571,9 @@ static void GetResourceAsStream(Thread* self, 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 @@ static void GetResourceAsStream(Thread* self, 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 d31f166869..37365ff9b5 100644 --- a/runtime/jdwp/jdwp_handler.cc +++ b/runtime/jdwp/jdwp_handler.cc @@ -292,8 +292,7 @@ static JdwpError VM_ClassPaths(JdwpState*, Request*, ExpandBuf* pReply) 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 e213dc79b8..3e5003ce13 100644 --- a/runtime/native/dalvik_system_VMRuntime.cc +++ b/runtime/native/dalvik_system_VMRuntime.cc @@ -24,7 +24,8 @@ extern "C" void android_set_application_target_sdk_version(uint32_t version); #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 const char* DefaultToDot(const std::string& class_path) { } 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 ee46f426cf..b09c81e3ad 100644 --- a/runtime/oat.h +++ b/runtime/oat.h @@ -31,8 +31,8 @@ class InstructionSetFeatures; 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 29b569050c..17ff3a244d 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 @@ std::unique_ptr<RuntimeParser> ParsedOptions::MakeParser(bool ignore_unrecognize .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 @@ bool ParsedOptions::DoParse(const RuntimeOptions& options, 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 @@ bool ParsedOptions::DoParse(const RuntimeOptions& options, } // 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 @@ bool ParsedOptions::DoParse(const RuntimeOptions& options, 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 705cc6c5e2..cbb7b825d3 100644 --- a/runtime/parsed_options_test.cc +++ b/runtime/parsed_options_test.cc @@ -40,8 +40,7 @@ TEST_F(ParsedOptionsTest, ParsedOptions) { 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 @@ TEST_F(ParsedOptionsTest, ParsedOptions) { 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 @@ TEST_F(ParsedOptionsTest, ParsedOptions) { 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 182319a27c..44e01c2575 100644 --- a/runtime/runtime.cc +++ b/runtime/runtime.cc @@ -1097,7 +1097,45 @@ bool Runtime::Init(RuntimeArgumentMap&& runtime_options_in) { 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 @@ bool Runtime::Init(RuntimeArgumentMap&& runtime_options_in) { } } 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 @@ bool Runtime::Init(RuntimeArgumentMap&& runtime_options_in) { 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 @@ bool Runtime::Init(RuntimeArgumentMap&& runtime_options_in) { 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 @@ bool Runtime::Init(RuntimeArgumentMap&& runtime_options_in) { 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 45333761af..b76a658b49 100644 --- a/runtime/runtime.h +++ b/runtime/runtime.h @@ -243,8 +243,14 @@ class Runtime { ~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 @@ class Runtime { 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 5cec309453..2b2919eff4 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 20e5c64eaa..f4a2dc1a6a 100755 --- a/tools/run-jdwp-tests.sh +++ b/tools/run-jdwp-tests.sh @@ -43,6 +43,22 @@ android_root=${ART_TEST_ANDROID_ROOT:-/system} 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 @@ debug="no" 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 @@ while true; do 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 @@ while true; do 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 @@ fi 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 @@ vogar $vm_command \ --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 2d39b2a9f8..63f1fce13f 100755 --- a/tools/run-libcore-tests.sh +++ b/tools/run-libcore-tests.sh @@ -46,6 +46,21 @@ function cparg { 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 @@ while true; do 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 |