bool CompareFiles(const std::string& filename1, const std::string& filename2) {
std::unique_ptr<File> file1(OS::OpenFileForReading(filename1.c_str()));
std::unique_ptr<File> file2(OS::OpenFileForReading(filename2.c_str())); // Did we open the files? if (file1 == nullptr || file2 == nullptr) { returnfalse;
} // Are they non-empty and the same length? if (file1->GetLength() <= 0 || file2->GetLength() != file1->GetLength()) { returnfalse;
} return file1->Compare(file2.get()) == 0;
}
// Maps prefix to a replacement runtime option.
std::vector<std::pair<std::string, std::pair<std::string, constvoid*>>>
runtime_option_overrides_; // Allow creating `Runtime` without compiler callbacks. bool runtime_option_no_compiler_callbacks_ = false;
};
TEST_F(Dex2oatImageTest, TestModesAndFilters) { // This test crashes on the gtest-heap-poisoning configuration // (AddressSanitizer + CMS/RosAlloc + heap-poisoning); see b/111061592. // Temporarily disable this test on this configuration to keep // our automated build/testing green while we work on a fix.
TEST_DISABLED_FOR_MEMORY_TOOL_WITH_HEAP_POISONING_WITHOUT_READ_BARRIERS(); if (kIsTargetBuild) { // This test is too slow for target builds. return;
} // Compile only a subset of the libcore dex files to make this test shorter.
std::vector<std::string> libcore_dex_files = GetLibCoreDexFileNames(); // The primary image must contain at least core-oj and core-libart to initialize the runtime.
ASSERT_NE(std::string::npos, libcore_dex_files[0].find("core-oj"));
ASSERT_NE(std::string::npos, libcore_dex_files[1].find("core-libart"));
ArrayRef<const std::string> dex_files =
ArrayRef<const std::string>(libcore_dex_files).SubArray(/*pos=*/ 0u, /*length=*/ 2u);
TEST_F(Dex2oatImageTest, TestExtension) { // TODO(b/376621099): investigate LUCI failures (timeouts?) and re-enable this test. // This is not related to riscv64 arch, but a combination of riscv64 and running on VM.
TEST_DISABLED_ON_RISCV64_VM();
// Copy the libcore dex files to a custom dir inside `scratch_dir` so that we do not // accidentally load pre-compiled core images from their original directory based on BCP paths.
std::string jar_dir = scratch_dir + "jars";
mkdir_result = mkdir(jar_dir.c_str(), 0700);
ASSERT_EQ(0, mkdir_result);
jar_dir += '/';
std::vector<std::string> libcore_dex_files = GetLibCoreDexFileNames();
CopyDexFiles(jar_dir, &libcore_dex_files);
ArrayRef<const std::string> full_bcp(libcore_dex_files);
size_t total_dex_files = full_bcp.size();
ASSERT_GE(total_dex_files, 4u); // 2 for "head", 1 for "tail", at least one for "mid", see below.
// The primary image must contain at least core-oj and core-libart to initialize the runtime.
ASSERT_NE(std::string::npos, full_bcp[0].find("core-oj"));
ASSERT_NE(std::string::npos, full_bcp[1].find("core-libart"));
ArrayRef<const std::string> head_dex_files = full_bcp.SubArray(/*pos=*/ 0u, /*length=*/ 2u); // Middle part is everything else except for conscrypt.
ASSERT_NE(std::string::npos, full_bcp[full_bcp.size() - 1u].find("conscrypt"));
ArrayRef<const std::string> mid_bcp =
full_bcp.SubArray(/*pos=*/ 0u, /*length=*/ total_dex_files - 1u);
ArrayRef<const std::string> mid_dex_files = mid_bcp.SubArray(/*pos=*/ 2u); // Tail is just the conscrypt.
ArrayRef<const std::string> tail_dex_files =
full_bcp.SubArray(/*pos=*/ total_dex_files - 1u, /*length=*/ 1u);
// Compile the "head", i.e. the primary boot image.
std::vector<std::string> extra_args;
extra_args.push_back("--profile-file=" + head_profile_filename);
extra_args.push_back(android::base::StringPrintf("--base=0x%08x", kBaseAddress)); bool head_ok = CompileBootImage(extra_args, filename_prefix, head_dex_files, &error_msg);
ASSERT_TRUE(head_ok) << error_msg;
// Compile the "mid", i.e. the first extension.
std::string mid_bcp_string = android::base::Join(mid_bcp, ':');
extra_args.clear();
extra_args.push_back("--profile-file=" + mid_profile_filename);
AddRuntimeArg(extra_args, "-Xbootclasspath:" + mid_bcp_string);
AddRuntimeArg(extra_args, "-Xbootclasspath-locations:" + mid_bcp_string);
extra_args.push_back("--boot-image=" + base_location); bool mid_ok = CompileBootImage(extra_args, filename_prefix, mid_dex_files, &error_msg);
ASSERT_TRUE(mid_ok) << error_msg;
// Try to compile the "tail" without specifying the "mid" extension. This shall fail.
extra_args.clear();
extra_args.push_back("--profile-file=" + tail_profile_filename);
std::string full_bcp_string = android::base::Join(full_bcp, ':');
AddRuntimeArg(extra_args, "-Xbootclasspath:" + full_bcp_string);
AddRuntimeArg(extra_args, "-Xbootclasspath-locations:" + full_bcp_string);
extra_args.push_back("--boot-image=" + base_location); bool tail_ok = CompileBootImage(extra_args, filename_prefix, tail_dex_files, &error_msg);
ASSERT_FALSE(tail_ok) << error_msg;
// Now compile the tail against both "head" and "mid".
CHECK(extra_args.back().starts_with("--boot-image="));
extra_args.back() = "--boot-image=" + base_location + ':' + mid_location;
tail_ok = CompileBootImage(extra_args, filename_prefix, tail_dex_files, &error_msg);
ASSERT_TRUE(tail_ok) << error_msg;
// Prepare directory for the single-image test that squashes the "mid" and "tail".
std::string single_dir = scratch_dir + "single";
mkdir_result = mkdir(single_dir.c_str(), 0700);
ASSERT_EQ(0, mkdir_result);
single_dir += '/';
std::string single_image_dir = single_dir + GetInstructionSetString(kRuntimeISA);
mkdir_result = mkdir(single_image_dir.c_str(), 0700);
ASSERT_EQ(0, mkdir_result);
std::string single_filename_prefix = single_image_dir + "/boot";
// The dex files for the single-image are everything not in the "head".
ArrayRef<const std::string> single_dex_files = full_bcp.SubArray(/*pos=*/ head_dex_files.size());
// Create a smaller profile for the single-image test that squashes the "mid" and "tail".
ScratchFile single_profile_file;
GenerateBootProfile(single_dex_files,
single_profile_file.GetFile(), /*method_frequency=*/ 5u, /*type_frequency=*/ 4u); const std::string& single_profile_filename = single_profile_file.GetFilename();
// Load primary image with full path. bool load_ok = load(base_location);
ASSERT_TRUE(load_ok) << error_msg;
ASSERT_FALSE(extra_reservation.IsValid());
ASSERT_EQ(head_dex_files.size(), boot_image_spaces.size());
// Fail to load primary image with just the name.
load_ok = silent_load(base_name);
ASSERT_FALSE(load_ok);
// Fail to load primary image with a search path.
load_ok = silent_load("*");
ASSERT_FALSE(load_ok);
load_ok = silent_load(scratch_dir + "*");
ASSERT_FALSE(load_ok);
// Load the primary and first extension with full path.
load_ok = load(ART_FORMAT("{}:{}", base_location, mid_location));
ASSERT_TRUE(load_ok) << error_msg;
ASSERT_EQ(mid_bcp.size(), boot_image_spaces.size());
// Load the primary with full path and fail to load first extension without full path.
load_ok = load(ART_FORMAT("{}:{}", base_location, mid_name));
ASSERT_TRUE(load_ok) << error_msg; // Primary image loaded successfully.
ASSERT_EQ(head_dex_files.size(), boot_image_spaces.size()); // But only the primary image.
// Load all the libcore images with full paths.
load_ok = load(ART_FORMAT("{}:{}:{}", base_location, mid_location, tail_location));
ASSERT_TRUE(load_ok) << error_msg;
ASSERT_EQ(full_bcp.size(), boot_image_spaces.size());
// Load the primary and first extension with full paths, fail to load second extension by name.
load_ok = load(ART_FORMAT("{}:{}:{}", base_location, mid_location, tail_name));
ASSERT_TRUE(load_ok) << error_msg;
ASSERT_EQ(mid_bcp.size(), boot_image_spaces.size());
// Load the primary with full path and fail to load first extension without full path, // fail to load second extension because it depends on the first.
load_ok = load(ART_FORMAT("{}:{}:{}", base_location, mid_name, tail_location));
ASSERT_TRUE(load_ok) << error_msg; // Primary image loaded successfully.
ASSERT_EQ(head_dex_files.size(), boot_image_spaces.size()); // But only the primary image.
// Load the primary with full path and extensions with a specified search path.
load_ok = load(ART_FORMAT("{}:{}*", base_location, scratch_dir));
ASSERT_TRUE(load_ok) << error_msg;
ASSERT_EQ(full_bcp.size(), boot_image_spaces.size());
// Load the primary with full path and fail to find extensions in BCP path.
load_ok = load(base_location + ":*");
ASSERT_TRUE(load_ok) << error_msg;
ASSERT_EQ(head_dex_files.size(), boot_image_spaces.size());
}
// Now copy the libcore dex files to the `scratch_dir` and retry loading the boot image // with BCP in the scratch_dir so that the images can be found based on BCP paths.
CopyDexFiles(scratch_dir, &boot_class_path);
for (bool r : { false, true }) {
relocate = r;
// Loading the primary image with just the name now succeeds. bool load_ok = load(base_name);
ASSERT_TRUE(load_ok) << error_msg;
ASSERT_EQ(head_dex_files.size(), boot_image_spaces.size());
// Loading the primary image with a search path still fails.
load_ok = silent_load("*");
ASSERT_FALSE(load_ok);
load_ok = silent_load(scratch_dir + "*");
ASSERT_FALSE(load_ok);
// Load the primary and first extension without paths.
load_ok = load(ART_FORMAT("{}:{}", base_name, mid_name));
ASSERT_TRUE(load_ok) << error_msg;
ASSERT_EQ(mid_bcp.size(), boot_image_spaces.size());
// Load the primary without path and first extension with path.
load_ok = load(ART_FORMAT("{}:{}", base_name, mid_location));
ASSERT_TRUE(load_ok) << error_msg;
ASSERT_EQ(mid_bcp.size(), boot_image_spaces.size());
// Load the primary with full path and the first extension without full path.
load_ok = load(ART_FORMAT("{}:{}", base_location, mid_name));
ASSERT_TRUE(load_ok) << error_msg; // Loaded successfully.
ASSERT_EQ(mid_bcp.size(), boot_image_spaces.size()); // Including the extension.
// Load all the libcore images without paths.
load_ok = load(ART_FORMAT("{}:{}:{}", base_name, mid_name, tail_name));
ASSERT_TRUE(load_ok) << error_msg;
ASSERT_EQ(full_bcp.size(), boot_image_spaces.size());
// Load the primary and first extension with full paths and second extension by name.
load_ok = load(ART_FORMAT("{}:{}:{}", base_location, mid_location, tail_name));
ASSERT_TRUE(load_ok) << error_msg;
ASSERT_EQ(full_bcp.size(), boot_image_spaces.size());
// Load the primary with full path, first extension without path, // and second extension with full path.
load_ok = load(ART_FORMAT("{}:{}:{}", base_location, mid_name, tail_location));
ASSERT_TRUE(load_ok) << error_msg; // Loaded successfully.
ASSERT_EQ(full_bcp.size(), boot_image_spaces.size()); // Including both extensions.
// Load the primary with full path and find both extensions in BCP path.
load_ok = load(base_location + ":*");
ASSERT_TRUE(load_ok) << error_msg;
ASSERT_EQ(full_bcp.size(), boot_image_spaces.size());
// Fail to load any images with invalid image locations (named component after search paths).
load_ok = silent_load(ART_FORMAT("{}:*:{}", base_location, tail_location));
ASSERT_FALSE(load_ok);
load_ok = silent_load(ART_FORMAT("{}:{}*:{}", base_location, scratch_dir, tail_location));
ASSERT_FALSE(load_ok);
// Load the primary and single-image extension with full path.
load_ok = load(ART_FORMAT("{}:{}", base_location, single_location));
ASSERT_TRUE(load_ok) << error_msg;
ASSERT_EQ(head_dex_files.size() + 1u, boot_image_spaces.size());
// Load the primary with full path and single-image extension with a specified search path.
load_ok = load(ART_FORMAT("{}:{}*", base_location, single_dir));
ASSERT_TRUE(load_ok) << error_msg;
ASSERT_EQ(head_dex_files.size() + 1u, boot_image_spaces.size());
}
// Test parsing profile specification and creating the boot image extension on-the-fly. // We must set --android-root in the image compiler options.
AddAndroidRootToImageCompilerOptions(); for (bool r : { false, true }) {
relocate = r;
// Load primary boot image with a profile name. bool load_ok = silent_load(ART_FORMAT("{}!{}", base_location, single_profile_filename));
ASSERT_TRUE(load_ok);
// Try and fail to load with invalid spec, two profile name separators.
load_ok =
silent_load(ART_FORMAT("{}:{}!!arbitrary-profile-name", base_location, single_location));
ASSERT_FALSE(load_ok);
// Try and fail to load with invalid spec, missing profile name.
load_ok = silent_load(ART_FORMAT("{}:{}!", base_location, single_location));
ASSERT_FALSE(load_ok);
// Try and fail to load with invalid spec, missing component name.
load_ok = silent_load(ART_FORMAT("{}:!{}", base_location, single_profile_filename));
ASSERT_FALSE(load_ok);
// Load primary boot image and the single extension, specifying invalid profile name. // (Load extension from file.)
load_ok = load(ART_FORMAT("{}:{}!non-existent-profile-name", base_location, single_location));
ASSERT_TRUE(load_ok) << error_msg;
ASSERT_EQ(head_dex_files.size() + 1u, boot_image_spaces.size());
ASSERT_EQ(single_dex_files.size(),
boot_image_spaces.back()->GetImageHeader().GetComponentCount());
// Load primary boot image and fail to load the single extension, specifying // invalid extension component name but a valid profile file. // (Running dex2oat to compile extension is disabled.)
ASSERT_FALSE(Runtime::Current()->IsImageDex2OatEnabled());
load_ok = load(
ART_FORMAT("{}:/non-existent/{}!{}", base_location, single_name, single_profile_filename));
ASSERT_TRUE(load_ok) << error_msg;
ASSERT_EQ(head_dex_files.size(), boot_image_spaces.size());
EnableImageDex2Oat();
// Load primary boot image and the single extension, specifying invalid extension // component name but a valid profile file. (Compile extension by running dex2oat.)
load_ok = load(
ART_FORMAT("{}:/non-existent/{}!{}", base_location, single_name, single_profile_filename));
ASSERT_TRUE(load_ok) << error_msg;
ASSERT_EQ(head_dex_files.size() + 1u, boot_image_spaces.size());
ASSERT_EQ(single_dex_files.size(),
boot_image_spaces.back()->GetImageHeader().GetComponentCount());
// Load primary boot image and fail to load extensions, specifying invalid component // names but valid profile file only for the second one. As we fail to load the first // extension, the second extension has a missing dependency and cannot be compiled.
load_ok = load(ART_FORMAT("{}:/non-existent/{}:/non-existent/{}!{}",
base_location,
mid_name,
tail_name,
tail_profile_filename));
ASSERT_TRUE(load_ok) << error_msg;
ASSERT_EQ(head_dex_files.size(), boot_image_spaces.size());
DisableImageDex2Oat();
}
}
TEST_F(Dex2oatImageTest, InlinedString) { // TODO(b/480856545): investigate and fix SIGSEGV that happens on LUCI
TEST_DISABLED_ON_VM();
// The primary image must contain at least core-oj and core-libart to initialize the runtime.
std::vector<std::string> bcp = GetLibCoreDexFileNames();
ASSERT_GE(bcp.size(), 2u);
ASSERT_NE(std::string::npos, bcp[0].find("core-oj"));
ASSERT_NE(std::string::npos, bcp[1].find("core-libart"));
bcp.resize(2u);
// Add `StringLiterals` and `InlinedString` to the boot class path. // When compiling `InlinedString.getUniqueStringFromStringLiterals()`, we shall inline // `HLoadString` from `StringLiterals.getUniqueString()`. That string does not have // a `StringId` in the `InlinedString` dex file but we want to include it in the boot // image extension anyway and that requires special handling in `ImageWriter`. // Otherwise, `dex2oat` would crash when trying to determine the string's image // address when processing the method's `LinkerPatch` for that string.
bcp.push_back(GetTestDexFileName("StringLiterals"));
bcp.push_back(GetTestDexFileName("InlinedString"));
// Copy the dex files to a custom dir inside `scratch_dir` so that we do not accidentally // try to load pre-compiled core images from their original directory based on BCP paths.
std::string jar_dir = scratch_dir + "jars";
mkdir_result = mkdir(jar_dir.c_str(), 0700);
ASSERT_EQ(0, mkdir_result);
jar_dir += '/';
CopyDexFiles(jar_dir, &bcp);
// Split the BCP to primary and extension (just the last dex file).
ArrayRef<const std::string> primary_dex_files =
ArrayRef<const std::string>(bcp).SubArray(/*pos=*/ 0u, /*length=*/ bcp.size() - 1u);
ArrayRef<const std::string> extension_dex_files =
ArrayRef<const std::string>(bcp).SubArray(/*pos=*/ bcp.size() - 1u, /*length=*/ 1u);
// Check that there is no String .bss entry in any boot image oat file. for (const std::unique_ptr<gc::space::ImageSpace>& space : boot_image_spaces) { const OatFile* oat_file = space->GetOatFile();
ASSERT_TRUE(oat_file != nullptr); for (constauto& info : oat_file->GetBcpBssInfo()) {
ASSERT_TRUE(info.string_bss_mapping == nullptr);
}
}
// Check the presence of the inlined string in the boot image extension. if (com::android::art::flags::weak_const_string()) { constchar kStringToFind[] = "Unique string for gtests from StringLiterals"; const size_t kStringToFindUtf16Length = /* Same as ASCII length. */ strlen(kStringToFind);
gc::space::ImageSpace* extension_space = boot_image_spaces.back().get(); const ImageSection& extension_interns =
extension_space->GetImageHeader().GetInternedStringsSection();
ASSERT_NE(extension_interns.Size(), 0u); const uint8_t* intern_data = extension_space->Begin() + extension_interns.Offset();
size_t read_count;
InternTable::UnorderedSet intern_set(intern_data, /*make_copy_of_data=*/ false, &read_count); auto it = intern_set.find(InternTable::Utf8String(kStringToFindUtf16Length, kStringToFind));
ASSERT_TRUE(it != intern_set.end());
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.