Refine OatStatus enum.
Replace Exists() with a separate OatStatus code, and distinguish
between the oat file being out of date due to the dex being out of
date or the image being out of date.
Bug: 30937355
Test: oat_file_assistant_test
Change-Id: Ia3853e461beb07f0b417276b9277b9c562b20865
diff --git a/build/Android.gtest.mk b/build/Android.gtest.mk
index 4fce235..9902628 100644
--- a/build/Android.gtest.mk
+++ b/build/Android.gtest.mk
@@ -116,10 +116,14 @@
ART_GTEST_dex2oat_environment_tests_HOST_DEPS := \
$(HOST_CORE_IMAGE_optimizing_pic_64) \
$(HOST_CORE_IMAGE_optimizing_pic_32) \
+ $(HOST_CORE_IMAGE_optimizing_no-pic_64) \
+ $(HOST_CORE_IMAGE_optimizing_no-pic_32) \
$(HOST_OUT_EXECUTABLES)/patchoatd
ART_GTEST_dex2oat_environment_tests_TARGET_DEPS := \
$(TARGET_CORE_IMAGE_optimizing_pic_64) \
$(TARGET_CORE_IMAGE_optimizing_pic_32) \
+ $(TARGET_CORE_IMAGE_optimizing_no-pic_64) \
+ $(TARGET_CORE_IMAGE_optimizing_no-pic_32) \
$(TARGET_OUT_EXECUTABLES)/patchoatd
ART_GTEST_oat_file_assistant_test_HOST_DEPS := \
diff --git a/runtime/dex2oat_environment_test.h b/runtime/dex2oat_environment_test.h
index d717ec0..b0c4597 100644
--- a/runtime/dex2oat_environment_test.h
+++ b/runtime/dex2oat_environment_test.h
@@ -136,7 +136,9 @@
+ "/core.art";
}
- bool GetCachedImageFile(/*out*/std::string* image, std::string* error_msg) const {
+ bool GetCachedImageFile(const std::string& image_location,
+ /*out*/std::string* image,
+ /*out*/std::string* error_msg) const {
std::string cache;
bool have_android_data;
bool dalvik_cache_exists;
@@ -151,7 +153,14 @@
*error_msg = "Failed to create dalvik cache";
return false;
}
- return GetDalvikCacheFilename(GetImageLocation().c_str(), cache.c_str(), image, error_msg);
+ return GetDalvikCacheFilename(image_location.c_str(), cache.c_str(), image, error_msg);
+ }
+
+ // Returns the path to an image location whose contents differ from the
+ // image at GetImageLocation(). This is used for testing mismatched
+ // image checksums in the oat_file_assistant_tests.
+ std::string GetImageLocation2() const {
+ return GetImageDirectory() + "/core-npic.art";
}
std::string GetDexSrc1() const {
diff --git a/runtime/oat_file_assistant.cc b/runtime/oat_file_assistant.cc
index c4ad98d..6197120 100644
--- a/runtime/oat_file_assistant.cc
+++ b/runtime/oat_file_assistant.cc
@@ -36,15 +36,21 @@
std::ostream& operator << (std::ostream& stream, const OatFileAssistant::OatStatus status) {
switch (status) {
- case OatFileAssistant::kOatOutOfDate:
- stream << "kOatOutOfDate";
+ case OatFileAssistant::kOatCannotOpen:
+ stream << "kOatCannotOpen";
+ break;
+ case OatFileAssistant::kOatDexOutOfDate:
+ stream << "kOatDexOutOfDate";
+ break;
+ case OatFileAssistant::kOatBootImageOutOfDate:
+ stream << "kOatBootImageOutOfDate";
+ break;
+ case OatFileAssistant::kOatRelocationOutOfDate:
+ stream << "kOatRelocationOutOfDate";
break;
case OatFileAssistant::kOatUpToDate:
stream << "kOatUpToDate";
break;
- case OatFileAssistant::kOatNeedsRelocation:
- stream << "kOatNeedsRelocation";
- break;
default:
UNREACHABLE();
}
@@ -204,20 +210,28 @@
std::ostringstream status;
bool oat_file_exists = false;
bool odex_file_exists = false;
- if (oat_.Exists()) {
+ if (oat_.Status() != kOatCannotOpen) {
+ // If we can open the file, neither Filename nor GetFile should return null.
+ CHECK(oat_.Filename() != nullptr);
+ CHECK(oat_.GetFile() != nullptr);
+
oat_file_exists = true;
status << *oat_.Filename() << " [compilation_filter=";
- status << CompilerFilter::NameOfFilter(oat_.CompilerFilter());
+ status << CompilerFilter::NameOfFilter(oat_.GetFile()->GetCompilerFilter());
status << ", status=" << oat_.Status();
}
- if (odex_.Exists()) {
+ if (odex_.Status() != kOatCannotOpen) {
+ // If we can open the file, neither Filename nor GetFile should return null.
+ CHECK(odex_.Filename() != nullptr);
+ CHECK(odex_.GetFile() != nullptr);
+
odex_file_exists = true;
if (oat_file_exists) {
status << "] ";
}
status << *odex_.Filename() << " [compilation_filter=";
- status << CompilerFilter::NameOfFilter(odex_.CompilerFilter());
+ status << CompilerFilter::NameOfFilter(odex_.GetFile()->GetCompilerFilter());
status << ", status=" << odex_.Status();
}
@@ -276,18 +290,10 @@
return has_original_dex_files_;
}
-bool OatFileAssistant::OdexFileExists() {
- return odex_.Exists();
-}
-
OatFileAssistant::OatStatus OatFileAssistant::OdexFileStatus() {
return odex_.Status();
}
-bool OatFileAssistant::OatFileExists() {
- return oat_.Exists();
-}
-
OatFileAssistant::OatStatus OatFileAssistant::OatFileStatus() {
return oat_.Status();
}
@@ -302,7 +308,7 @@
dex_location_.c_str(), dex_checksum_pointer, &error_msg);
if (oat_dex_file == nullptr) {
VLOG(oat) << error_msg;
- return kOatOutOfDate;
+ return kOatDexOutOfDate;
}
// Verify the dex checksums for any secondary multidex files
@@ -325,7 +331,7 @@
<< secondary_dex_location
<< ". Expected: " << expected_secondary_checksum
<< ", Actual: " << actual_secondary_checksum;
- return kOatOutOfDate;
+ return kOatDexOutOfDate;
}
} else {
// If we can't get the checksum for the secondary location, we assume
@@ -344,7 +350,7 @@
VLOG(oat) << "No image for oat image checksum to match against.";
if (HasOriginalDexFiles()) {
- return kOatOutOfDate;
+ return kOatBootImageOutOfDate;
}
// If there is no original dex file to fall back to, grudgingly accept
@@ -358,7 +364,7 @@
} else if (file.GetOatHeader().GetImageFileLocationOatChecksum()
!= GetCombinedImageChecksum()) {
VLOG(oat) << "Oat image checksum does not match image checksum.";
- return kOatOutOfDate;
+ return kOatBootImageOutOfDate;
}
} else {
VLOG(oat) << "Image checksum test skipped for compiler filter " << current_compiler_filter;
@@ -369,7 +375,7 @@
const ImageInfo* image_info = GetImageInfo();
if (image_info == nullptr) {
VLOG(oat) << "No image to check oat relocation against.";
- return kOatNeedsRelocation;
+ return kOatRelocationOutOfDate;
}
// Verify the oat_data_begin recorded for the image in the oat file matches
@@ -381,7 +387,7 @@
": Oat file image oat_data_begin (" << oat_data_begin << ")"
<< " does not match actual image oat_data_begin ("
<< image_info->oat_data_begin << ")";
- return kOatNeedsRelocation;
+ return kOatRelocationOutOfDate;
}
// Verify the oat_patch_delta recorded for the image in the oat file matches
@@ -392,7 +398,7 @@
": Oat file image patch delta (" << oat_patch_delta << ")"
<< " does not match actual image patch delta ("
<< image_info->patch_delta << ")";
- return kOatNeedsRelocation;
+ return kOatRelocationOutOfDate;
}
} else {
// Oat files compiled in PIC mode do not require relocation.
@@ -761,7 +767,8 @@
}
OatFileAssistant::OatFileInfo& OatFileAssistant::GetBestInfo() {
- return oat_.Status() != kOatOutOfDate ? oat_ : odex_;
+ bool use_oat = oat_.IsUseable() || odex_.Status() == kOatCannotOpen;
+ return use_oat ? oat_ : odex_;
}
std::unique_ptr<gc::space::ImageSpace> OatFileAssistant::OpenImageSpace(const OatFile* oat_file) {
@@ -793,8 +800,16 @@
return filename_provided_ ? &filename_ : nullptr;
}
-bool OatFileAssistant::OatFileInfo::Exists() {
- return GetFile() != nullptr;
+bool OatFileAssistant::OatFileInfo::IsUseable() {
+ switch (Status()) {
+ case kOatCannotOpen:
+ case kOatDexOutOfDate:
+ case kOatBootImageOutOfDate: return false;
+
+ case kOatRelocationOutOfDate:
+ case kOatUpToDate: return true;
+ }
+ UNREACHABLE();
}
OatFileAssistant::OatStatus OatFileAssistant::OatFileInfo::Status() {
@@ -802,7 +817,7 @@
status_attempted_ = true;
const OatFile* file = GetFile();
if (file == nullptr) {
- status_ = kOatOutOfDate;
+ status_ = kOatCannotOpen;
} else {
status_ = oat_file_assistant_->GivenOatFileStatus(*file);
VLOG(oat) << file->GetLocation() << " is " << status_
@@ -812,12 +827,6 @@
return status_;
}
-CompilerFilter::Filter OatFileAssistant::OatFileInfo::CompilerFilter() {
- const OatFile* file = GetFile();
- CHECK(file != nullptr);
- return file->GetCompilerFilter();
-}
-
OatFileAssistant::DexOptNeeded OatFileAssistant::OatFileInfo::GetDexOptNeeded(
CompilerFilter::Filter target, bool profile_changed) {
bool compilation_desired = CompilerFilter::IsBytecodeCompilationEnabled(target);
@@ -828,7 +837,7 @@
return kNoDexOptNeeded;
}
- if (Status() == kOatNeedsRelocation) {
+ if (Status() == kOatRelocationOutOfDate) {
if (!compilation_desired) {
// If no compilation is desired, then it doesn't matter if the oat
// file needs relocation. It's in good shape as is.
@@ -919,18 +928,18 @@
VLOG(oat) << "Oat File Assistant: No relocated oat file found,"
<< " attempting to fall back to interpreting oat file instead.";
- if (Status() == kOatNeedsRelocation && !IsExecutable()) {
+ if (Status() == kOatRelocationOutOfDate && !IsExecutable()) {
return ReleaseFile();
}
- if (Status() == kOatNeedsRelocation) {
+ if (Status() == kOatRelocationOutOfDate) {
// We are loading an oat file for runtime use that needs relocation.
// Reload the file non-executable to ensure that we interpret out of the
// dex code in the oat file rather than trying to execute the unrelocated
// compiled code.
oat_file_assistant_->load_executable_ = false;
Reset();
- if (Status() != kOatOutOfDate) {
+ if (IsUseable()) {
CHECK(!IsExecutable());
return ReleaseFile();
}
diff --git a/runtime/oat_file_assistant.h b/runtime/oat_file_assistant.h
index 14bd82f..3a838d7 100644
--- a/runtime/oat_file_assistant.h
+++ b/runtime/oat_file_assistant.h
@@ -70,19 +70,26 @@
};
enum OatStatus {
- // kOatOutOfDate - An oat file is said to be out of date if the file does
- // not exist, is out of date with respect to the dex file or boot image,
- // or does not meet the target compilation type.
- kOatOutOfDate,
+ // kOatCannotOpen - The oat file cannot be opened, because it does not
+ // exist, is unreadable, or otherwise corrupted.
+ kOatCannotOpen,
- // kOatNeedsRelocation - An oat file is said to need relocation if the
- // code is up to date, but not yet properly relocated for address space
- // layout randomization (ASLR). In this case, the oat file is neither
- // "out of date" nor "up to date".
- kOatNeedsRelocation,
+ // kOatDexOutOfDate - The oat file is out of date with respect to the dex file.
+ kOatDexOutOfDate,
- // kOatUpToDate - An oat file is said to be up to date if it is not out of
- // date and has been properly relocated for the purposes of ASLR.
+ // kOatBootImageOutOfDate - The oat file is up to date with respect to the
+ // dex file, but is out of date with respect to the boot image.
+ kOatBootImageOutOfDate,
+
+ // kOatRelocationOutOfDate - The oat file is up to date with respect to
+ // the dex file and boot image, but contains compiled code that has the
+ // wrong patch delta with respect to the boot image. Patchoat should be
+ // run on the oat file to update the patch delta of the compiled code to
+ // match the boot image.
+ kOatRelocationOutOfDate,
+
+ // kOatUpToDate - The oat file is completely up to date with respect to
+ // the dex file and boot image.
kOatUpToDate,
};
@@ -209,23 +216,17 @@
// really an oat file. The odex file will often, but not always, have a
// patch delta of 0 and need to be relocated before use for the purposes of
// ASLR. The odex file is treated as if it were read-only.
- // These methods return the location and status of the odex file for the dex
- // location.
- bool OdexFileExists();
+ //
+ // Returns the status of the odex file for the dex location.
OatStatus OdexFileStatus();
// When the dex files is compiled on the target device, the oat file is the
// result. The oat file will have been relocated to some
// (possibly-out-of-date) offset for ASLR.
- // These methods return the location and status of the target oat file for
- // the dex location.
- bool OatFileExists();
+ //
+ // Returns the status of the oat file for the dex location.
OatStatus OatFileStatus();
- // Return the status for a given opened oat file with respect to the dex
- // location.
- OatStatus GivenOatFileStatus(const OatFile& file);
-
// Generates the oat file by relocation from the named input file.
// This does not check the current status before attempting to relocate the
// oat file.
@@ -301,11 +302,17 @@
bool IsOatLocation();
const std::string* Filename();
- bool Exists();
+
+ // Returns true if this oat file can be used for running code. The oat
+ // file can be used for running code as long as it is not out of date with
+ // respect to the dex code or boot image. An oat file that is out of date
+ // with respect to relocation is considered useable, because it's possible
+ // to interpret the dex code rather than run the unrelocated compiled
+ // code.
+ bool IsUseable();
+
+ // Returns the status of this oat file.
OatStatus Status();
- // Must only be called if the associated file exists, i.e, if
- // |Exists() == true|.
- CompilerFilter::Filter CompilerFilter();
// Return the DexOptNeeded value for this oat file with respect to the
// given target_compilation_filter.
@@ -381,6 +388,10 @@
// Return info for the best oat file.
OatFileInfo& GetBestInfo();
+ // Return the status for a given opened oat file with respect to the dex
+ // location.
+ OatStatus GivenOatFileStatus(const OatFile& file);
+
// Returns the current image location.
// Returns an empty string if the image location could not be retrieved.
//
diff --git a/runtime/oat_file_assistant_test.cc b/runtime/oat_file_assistant_test.cc
index abd3b96..1848255 100644
--- a/runtime/oat_file_assistant_test.cc
+++ b/runtime/oat_file_assistant_test.cc
@@ -49,9 +49,9 @@
// Pre-Relocate the image to a known non-zero offset so we don't have to
// deal with the runtime randomly relocating the image by 0 and messing up
// the expected results of the tests.
- bool PreRelocateImage(std::string* error_msg) {
+ bool PreRelocateImage(const std::string& image_location, std::string* error_msg) {
std::string image;
- if (!GetCachedImageFile(&image, error_msg)) {
+ if (!GetCachedImageFile(image_location, &image, error_msg)) {
return false;
}
@@ -60,7 +60,7 @@
std::vector<std::string> argv;
argv.push_back(patchoat);
- argv.push_back("--input-image-location=" + GetImageLocation());
+ argv.push_back("--input-image-location=" + image_location);
argv.push_back("--output-image-file=" + image);
argv.push_back("--instruction-set=" + std::string(GetInstructionSetString(kRuntimeISA)));
argv.push_back("--base-offset-delta=0x00008000");
@@ -69,8 +69,8 @@
virtual void PreRuntimeCreate() {
std::string error_msg;
- ASSERT_TRUE(PreRelocateImage(&error_msg)) << error_msg;
-
+ ASSERT_TRUE(PreRelocateImage(GetImageLocation(), &error_msg)) << error_msg;
+ ASSERT_TRUE(PreRelocateImage(GetImageLocation2(), &error_msg)) << error_msg;
UnreserveImageSpace();
}
@@ -78,24 +78,32 @@
ReserveImageSpace();
}
- // Generate a non-PIC odex file for the purposes of test.
- // The generated odex file will be un-relocated.
- void GenerateOdexForTest(const std::string& dex_location,
- const std::string& odex_location,
- CompilerFilter::Filter filter,
- bool pic = false,
- bool with_patch_info = true) {
- // Temporarily redirect the dalvik cache so dex2oat doesn't find the
- // relocated image file.
+ // Generate an oat file for the purposes of test.
+ void GenerateOatForTest(const std::string& dex_location,
+ const std::string& oat_location,
+ CompilerFilter::Filter filter,
+ bool relocate,
+ bool pic,
+ bool with_patch_info,
+ bool with_alternate_image) {
std::string dalvik_cache = GetDalvikCache(GetInstructionSetString(kRuntimeISA));
std::string dalvik_cache_tmp = dalvik_cache + ".redirected";
- ASSERT_EQ(0, rename(dalvik_cache.c_str(), dalvik_cache_tmp.c_str())) << strerror(errno);
+
+ if (!relocate) {
+ // Temporarily redirect the dalvik cache so dex2oat doesn't find the
+ // relocated image file.
+ ASSERT_EQ(0, rename(dalvik_cache.c_str(), dalvik_cache_tmp.c_str())) << strerror(errno);
+ }
std::vector<std::string> args;
args.push_back("--dex-file=" + dex_location);
- args.push_back("--oat-file=" + odex_location);
+ args.push_back("--oat-file=" + oat_location);
args.push_back("--compiler-filter=" + CompilerFilter::NameOfFilter(filter));
args.push_back("--runtime-arg");
+
+ // Use -Xnorelocate regardless of the relocate argument.
+ // We control relocation by redirecting the dalvik cache when needed
+ // rather than use this flag.
args.push_back("-Xnorelocate");
if (pic) {
@@ -106,14 +114,22 @@
args.push_back("--include-patch-information");
}
+ std::string image_location = GetImageLocation();
+ if (with_alternate_image) {
+ args.push_back("--boot-image=" + GetImageLocation2());
+ }
+
std::string error_msg;
ASSERT_TRUE(OatFileAssistant::Dex2Oat(args, &error_msg)) << error_msg;
- ASSERT_EQ(0, rename(dalvik_cache_tmp.c_str(), dalvik_cache.c_str())) << strerror(errno);
- // Verify the odex file was generated as expected and really is
- // unrelocated.
- std::unique_ptr<OatFile> odex_file(OatFile::Open(odex_location.c_str(),
- odex_location.c_str(),
+ if (!relocate) {
+ // Restore the dalvik cache if needed.
+ ASSERT_EQ(0, rename(dalvik_cache_tmp.c_str(), dalvik_cache.c_str())) << strerror(errno);
+ }
+
+ // Verify the odex file was generated as expected.
+ std::unique_ptr<OatFile> odex_file(OatFile::Open(oat_location.c_str(),
+ oat_location.c_str(),
nullptr,
nullptr,
false,
@@ -125,24 +141,59 @@
EXPECT_EQ(with_patch_info, odex_file->HasPatchInfo());
EXPECT_EQ(filter, odex_file->GetCompilerFilter());
- if (CompilerFilter::IsBytecodeCompilationEnabled(filter)) {
- const std::vector<gc::space::ImageSpace*> image_spaces =
- Runtime::Current()->GetHeap()->GetBootImageSpaces();
- ASSERT_TRUE(!image_spaces.empty() && image_spaces[0] != nullptr);
- const ImageHeader& image_header = image_spaces[0]->GetImageHeader();
- const OatHeader& oat_header = odex_file->GetOatHeader();
- uint32_t combined_checksum = OatFileAssistant::CalculateCombinedImageChecksum();
- EXPECT_EQ(combined_checksum, oat_header.GetImageFileLocationOatChecksum());
- EXPECT_NE(reinterpret_cast<uintptr_t>(image_header.GetOatDataBegin()),
- oat_header.GetImageFileLocationOatDataBegin());
- EXPECT_NE(image_header.GetPatchDelta(), oat_header.GetImagePatchDelta());
+ std::unique_ptr<ImageHeader> image_header(
+ gc::space::ImageSpace::ReadImageHeader(image_location.c_str(),
+ kRuntimeISA,
+ &error_msg));
+ ASSERT_TRUE(image_header != nullptr) << error_msg;
+ const OatHeader& oat_header = odex_file->GetOatHeader();
+ uint32_t combined_checksum = OatFileAssistant::CalculateCombinedImageChecksum();
+
+ if (CompilerFilter::DependsOnImageChecksum(filter)) {
+ if (with_alternate_image) {
+ EXPECT_NE(combined_checksum, oat_header.GetImageFileLocationOatChecksum());
+ } else {
+ EXPECT_EQ(combined_checksum, oat_header.GetImageFileLocationOatChecksum());
+ }
}
+
+ if (CompilerFilter::IsBytecodeCompilationEnabled(filter)) {
+ if (relocate) {
+ EXPECT_EQ(reinterpret_cast<uintptr_t>(image_header->GetOatDataBegin()),
+ oat_header.GetImageFileLocationOatDataBegin());
+ EXPECT_EQ(image_header->GetPatchDelta(), oat_header.GetImagePatchDelta());
+ } else {
+ EXPECT_NE(reinterpret_cast<uintptr_t>(image_header->GetOatDataBegin()),
+ oat_header.GetImageFileLocationOatDataBegin());
+ EXPECT_NE(image_header->GetPatchDelta(), oat_header.GetImagePatchDelta());
+ }
+ }
+ }
+
+ // Generate a non-PIC odex file for the purposes of test.
+ // The generated odex file will be un-relocated.
+ void GenerateOdexForTest(const std::string& dex_location,
+ const std::string& odex_location,
+ CompilerFilter::Filter filter) {
+ GenerateOatForTest(dex_location,
+ odex_location,
+ filter,
+ /*relocate*/false,
+ /*pic*/false,
+ /*with_patch_info*/true,
+ /*with_alternate_image*/false);
}
void GeneratePicOdexForTest(const std::string& dex_location,
const std::string& odex_location,
CompilerFilter::Filter filter) {
- GenerateOdexForTest(dex_location, odex_location, filter, true, false);
+ GenerateOatForTest(dex_location,
+ odex_location,
+ filter,
+ /*relocate*/false,
+ /*pic*/true,
+ /*with_patch_info*/false,
+ /*with_alternate_image*/false);
}
// Generate a non-PIC odex file without patch information for the purposes
@@ -150,7 +201,43 @@
void GenerateNoPatchOdexForTest(const std::string& dex_location,
const std::string& odex_location,
CompilerFilter::Filter filter) {
- GenerateOdexForTest(dex_location, odex_location, filter, false, false);
+ GenerateOatForTest(dex_location,
+ odex_location,
+ filter,
+ /*relocate*/false,
+ /*pic*/false,
+ /*with_patch_info*/false,
+ /*with_alternate_image*/false);
+ }
+
+ // Generate an oat file in the oat location.
+ void GenerateOatForTest(const char* dex_location,
+ CompilerFilter::Filter filter,
+ bool relocate,
+ bool pic,
+ bool with_patch_info,
+ bool with_alternate_image) {
+ std::string oat_location;
+ std::string error_msg;
+ ASSERT_TRUE(OatFileAssistant::DexLocationToOatFilename(
+ dex_location, kRuntimeISA, &oat_location, &error_msg)) << error_msg;
+ GenerateOatForTest(dex_location,
+ oat_location,
+ filter,
+ relocate,
+ pic,
+ with_patch_info,
+ with_alternate_image);
+ }
+
+ // Generate a standard oat file in the oat location.
+ void GenerateOatForTest(const char* dex_location, CompilerFilter::Filter filter) {
+ GenerateOatForTest(dex_location,
+ filter,
+ /*relocate*/true,
+ /*pic*/false,
+ /*with_patch_info*/false,
+ /*with_alternate_image*/false);
}
private:
@@ -211,36 +298,6 @@
}
};
-// Generate an oat file for the purposes of test, as opposed to testing
-// generation of oat files.
-static void GenerateOatForTest(const char* dex_location, CompilerFilter::Filter filter) {
- // Use an oat file assistant to find the proper oat location.
- std::string oat_location;
- std::string error_msg;
- ASSERT_TRUE(OatFileAssistant::DexLocationToOatFilename(
- dex_location, kRuntimeISA, &oat_location, &error_msg)) << error_msg;
-
- std::vector<std::string> args;
- args.push_back("--dex-file=" + std::string(dex_location));
- args.push_back("--oat-file=" + oat_location);
- args.push_back("--compiler-filter=" + CompilerFilter::NameOfFilter(filter));
- args.push_back("--runtime-arg");
- args.push_back("-Xnorelocate");
- ASSERT_TRUE(OatFileAssistant::Dex2Oat(args, &error_msg)) << error_msg;
-
- // Verify the oat file was generated as expected.
- std::unique_ptr<OatFile> oat_file(OatFile::Open(oat_location.c_str(),
- oat_location.c_str(),
- nullptr,
- nullptr,
- false,
- /*low_4gb*/false,
- dex_location,
- &error_msg));
- ASSERT_TRUE(oat_file.get() != nullptr) << error_msg;
- EXPECT_EQ(filter, oat_file->GetCompilerFilter());
-}
-
// Case: We have a DEX file, but no OAT file for it.
// Expect: The status is kDex2OatNeeded.
TEST_F(OatFileAssistantTest, DexNoOat) {
@@ -259,10 +316,8 @@
oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
- EXPECT_FALSE(oat_file_assistant.OdexFileExists());
- EXPECT_EQ(OatFileAssistant::kOatOutOfDate, oat_file_assistant.OdexFileStatus());
- EXPECT_FALSE(oat_file_assistant.OatFileExists());
- EXPECT_EQ(OatFileAssistant::kOatOutOfDate, oat_file_assistant.OatFileStatus());
+ EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OdexFileStatus());
+ EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OatFileStatus());
EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles());
}
@@ -305,9 +360,7 @@
oat_file_assistant.GetDexOptNeeded(CompilerFilter::kEverything));
EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
- EXPECT_FALSE(oat_file_assistant.OdexFileExists());
- EXPECT_EQ(OatFileAssistant::kOatOutOfDate, oat_file_assistant.OdexFileStatus());
- EXPECT_TRUE(oat_file_assistant.OatFileExists());
+ EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OdexFileStatus());
EXPECT_EQ(OatFileAssistant::kOatUpToDate, oat_file_assistant.OatFileStatus());
EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles());
}
@@ -331,10 +384,8 @@
oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
- EXPECT_TRUE(oat_file_assistant.OdexFileExists());
- EXPECT_EQ(OatFileAssistant::kOatOutOfDate, oat_file_assistant.OdexFileStatus());
- EXPECT_FALSE(oat_file_assistant.OatFileExists());
- EXPECT_EQ(OatFileAssistant::kOatOutOfDate, oat_file_assistant.OatFileStatus());
+ EXPECT_EQ(OatFileAssistant::kOatDexOutOfDate, oat_file_assistant.OdexFileStatus());
+ EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OatFileStatus());
}
// Case: We have a DEX file and speed-profile OAT file for it.
@@ -357,9 +408,7 @@
oat_file_assistant.GetDexOptNeeded(CompilerFilter::kInterpretOnly, true));
EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
- EXPECT_FALSE(oat_file_assistant.OdexFileExists());
- EXPECT_EQ(OatFileAssistant::kOatOutOfDate, oat_file_assistant.OdexFileStatus());
- EXPECT_TRUE(oat_file_assistant.OatFileExists());
+ EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OdexFileStatus());
EXPECT_EQ(OatFileAssistant::kOatUpToDate, oat_file_assistant.OatFileStatus());
EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles());
}
@@ -436,10 +485,10 @@
EXPECT_EQ(2u, dex_files.size());
}
-// Case: We have a DEX file and out-of-date OAT file.
-// Expect: The status is kDex2OatNeeded.
-TEST_F(OatFileAssistantTest, OatOutOfDate) {
- std::string dex_location = GetScratchDir() + "/OatOutOfDate.jar";
+// Case: We have a DEX file and an OAT file out of date with respect to the
+// dex checksum.
+TEST_F(OatFileAssistantTest, OatDexOutOfDate) {
+ std::string dex_location = GetScratchDir() + "/OatDexOutOfDate.jar";
// We create a dex, generate an oat for it, then overwrite the dex with a
// different dex to make the oat out of date.
@@ -454,10 +503,62 @@
oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
- EXPECT_FALSE(oat_file_assistant.OdexFileExists());
- EXPECT_EQ(OatFileAssistant::kOatOutOfDate, oat_file_assistant.OdexFileStatus());
- EXPECT_TRUE(oat_file_assistant.OatFileExists());
- EXPECT_EQ(OatFileAssistant::kOatOutOfDate, oat_file_assistant.OatFileStatus());
+ EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OdexFileStatus());
+ EXPECT_EQ(OatFileAssistant::kOatDexOutOfDate, oat_file_assistant.OatFileStatus());
+ EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles());
+}
+
+// Case: We have a DEX file and an OAT file out of date with respect to the
+// boot image.
+TEST_F(OatFileAssistantTest, OatImageOutOfDate) {
+ std::string dex_location = GetScratchDir() + "/OatImageOutOfDate.jar";
+
+ Copy(GetDexSrc1(), dex_location);
+ GenerateOatForTest(dex_location.c_str(),
+ CompilerFilter::kSpeed,
+ /*relocate*/true,
+ /*pic*/false,
+ /*with_patch_info*/false,
+ /*with_alternate_image*/true);
+
+ OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
+ EXPECT_EQ(OatFileAssistant::kDex2OatNeeded,
+ oat_file_assistant.GetDexOptNeeded(CompilerFilter::kVerifyAtRuntime));
+ EXPECT_EQ(OatFileAssistant::kDex2OatNeeded,
+ oat_file_assistant.GetDexOptNeeded(CompilerFilter::kInterpretOnly));
+ EXPECT_EQ(OatFileAssistant::kDex2OatNeeded,
+ oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
+
+ EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
+ EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OdexFileStatus());
+ EXPECT_EQ(OatFileAssistant::kOatBootImageOutOfDate, oat_file_assistant.OatFileStatus());
+ EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles());
+}
+
+// Case: We have a DEX file and a verify-at-runtime OAT file out of date with
+// respect to the boot image.
+// It shouldn't matter that the OAT file is out of date, because it is
+// verify-at-runtime.
+TEST_F(OatFileAssistantTest, OatVerifyAtRuntimeImageOutOfDate) {
+ std::string dex_location = GetScratchDir() + "/OatVerifyAtRuntimeImageOutOfDate.jar";
+
+ Copy(GetDexSrc1(), dex_location);
+ GenerateOatForTest(dex_location.c_str(),
+ CompilerFilter::kVerifyAtRuntime,
+ /*relocate*/true,
+ /*pic*/false,
+ /*with_patch_info*/false,
+ /*with_alternate_image*/true);
+
+ OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
+ EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
+ oat_file_assistant.GetDexOptNeeded(CompilerFilter::kVerifyAtRuntime));
+ EXPECT_EQ(OatFileAssistant::kDex2OatNeeded,
+ oat_file_assistant.GetDexOptNeeded(CompilerFilter::kInterpretOnly));
+
+ EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
+ EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OdexFileStatus());
+ EXPECT_EQ(OatFileAssistant::kOatUpToDate, oat_file_assistant.OatFileStatus());
EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles());
}
@@ -480,10 +581,8 @@
oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
- EXPECT_TRUE(oat_file_assistant.OdexFileExists());
- EXPECT_EQ(OatFileAssistant::kOatNeedsRelocation, oat_file_assistant.OdexFileStatus());
- EXPECT_FALSE(oat_file_assistant.OatFileExists());
- EXPECT_EQ(OatFileAssistant::kOatOutOfDate, oat_file_assistant.OatFileStatus());
+ EXPECT_EQ(OatFileAssistant::kOatRelocationOutOfDate, oat_file_assistant.OdexFileStatus());
+ EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OatFileStatus());
EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles());
// We should still be able to get the non-executable odex file to run from.
@@ -511,10 +610,8 @@
oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
- EXPECT_TRUE(oat_file_assistant.OdexFileExists());
- EXPECT_EQ(OatFileAssistant::kOatNeedsRelocation, oat_file_assistant.OdexFileStatus());
- EXPECT_FALSE(oat_file_assistant.OatFileExists());
- EXPECT_EQ(OatFileAssistant::kOatOutOfDate, oat_file_assistant.OatFileStatus());
+ EXPECT_EQ(OatFileAssistant::kOatRelocationOutOfDate, oat_file_assistant.OdexFileStatus());
+ EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OatFileStatus());
EXPECT_FALSE(oat_file_assistant.HasOriginalDexFiles());
// Make the oat file up to date.
@@ -527,9 +624,7 @@
oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
- EXPECT_TRUE(oat_file_assistant.OdexFileExists());
- EXPECT_EQ(OatFileAssistant::kOatNeedsRelocation, oat_file_assistant.OdexFileStatus());
- EXPECT_TRUE(oat_file_assistant.OatFileExists());
+ EXPECT_EQ(OatFileAssistant::kOatRelocationOutOfDate, oat_file_assistant.OdexFileStatus());
EXPECT_EQ(OatFileAssistant::kOatUpToDate, oat_file_assistant.OatFileStatus());
EXPECT_FALSE(oat_file_assistant.HasOriginalDexFiles());
@@ -570,10 +665,8 @@
oat_file_assistant.GetDexOptNeeded(CompilerFilter::kEverything));
EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
- EXPECT_TRUE(oat_file_assistant.OdexFileExists());
- EXPECT_EQ(OatFileAssistant::kOatNeedsRelocation, oat_file_assistant.OdexFileStatus());
- EXPECT_TRUE(oat_file_assistant.OatFileExists());
- EXPECT_EQ(OatFileAssistant::kOatOutOfDate, oat_file_assistant.OatFileStatus());
+ EXPECT_EQ(OatFileAssistant::kOatRelocationOutOfDate, oat_file_assistant.OdexFileStatus());
+ EXPECT_EQ(OatFileAssistant::kOatDexOutOfDate, oat_file_assistant.OatFileStatus());
EXPECT_FALSE(oat_file_assistant.HasOriginalDexFiles());
// Make the oat file up to date.
@@ -588,10 +681,7 @@
oat_file_assistant.GetDexOptNeeded(CompilerFilter::kEverything));
EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
- EXPECT_TRUE(oat_file_assistant.OdexFileExists());
- EXPECT_EQ(OatFileAssistant::kOatNeedsRelocation, oat_file_assistant.OdexFileStatus());
-
- EXPECT_TRUE(oat_file_assistant.OatFileExists());
+ EXPECT_EQ(OatFileAssistant::kOatRelocationOutOfDate, oat_file_assistant.OdexFileStatus());
EXPECT_EQ(OatFileAssistant::kOatUpToDate, oat_file_assistant.OatFileStatus());
EXPECT_FALSE(oat_file_assistant.HasOriginalDexFiles());
@@ -622,10 +712,8 @@
oat_file_assistant.GetDexOptNeeded(CompilerFilter::kInterpretOnly));
EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
- EXPECT_FALSE(oat_file_assistant.OdexFileExists());
- EXPECT_EQ(OatFileAssistant::kOatOutOfDate, oat_file_assistant.OdexFileStatus());
- EXPECT_FALSE(oat_file_assistant.OatFileExists());
- EXPECT_EQ(OatFileAssistant::kOatOutOfDate, oat_file_assistant.OatFileStatus());
+ EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OdexFileStatus());
+ EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OatFileStatus());
EXPECT_FALSE(oat_file_assistant.HasOriginalDexFiles());
// Make the oat file up to date. This should have no effect.
@@ -638,10 +726,8 @@
oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
- EXPECT_FALSE(oat_file_assistant.OdexFileExists());
- EXPECT_EQ(OatFileAssistant::kOatOutOfDate, oat_file_assistant.OdexFileStatus());
- EXPECT_FALSE(oat_file_assistant.OatFileExists());
- EXPECT_EQ(OatFileAssistant::kOatOutOfDate, oat_file_assistant.OatFileStatus());
+ EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OdexFileStatus());
+ EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OatFileStatus());
EXPECT_FALSE(oat_file_assistant.HasOriginalDexFiles());
}
@@ -667,10 +753,8 @@
oat_file_assistant.GetDexOptNeeded(CompilerFilter::kEverything));
EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
- EXPECT_FALSE(oat_file_assistant.OdexFileExists());
- EXPECT_EQ(OatFileAssistant::kOatOutOfDate, oat_file_assistant.OdexFileStatus());
- EXPECT_TRUE(oat_file_assistant.OatFileExists());
- EXPECT_EQ(OatFileAssistant::kOatNeedsRelocation, oat_file_assistant.OatFileStatus());
+ EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OdexFileStatus());
+ EXPECT_EQ(OatFileAssistant::kOatRelocationOutOfDate, oat_file_assistant.OatFileStatus());
EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles());
// Make the oat file up to date.
@@ -683,9 +767,7 @@
oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
- EXPECT_FALSE(oat_file_assistant.OdexFileExists());
- EXPECT_EQ(OatFileAssistant::kOatOutOfDate, oat_file_assistant.OdexFileStatus());
- EXPECT_TRUE(oat_file_assistant.OatFileExists());
+ EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OdexFileStatus());
EXPECT_EQ(OatFileAssistant::kOatUpToDate, oat_file_assistant.OatFileStatus());
EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles());
@@ -757,10 +839,8 @@
oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
- EXPECT_TRUE(oat_file_assistant.OdexFileExists());
- EXPECT_EQ(OatFileAssistant::kOatNeedsRelocation, oat_file_assistant.OdexFileStatus());
- EXPECT_TRUE(oat_file_assistant.OatFileExists());
- EXPECT_EQ(OatFileAssistant::kOatNeedsRelocation, oat_file_assistant.OatFileStatus());
+ EXPECT_EQ(OatFileAssistant::kOatRelocationOutOfDate, oat_file_assistant.OdexFileStatus());
+ EXPECT_EQ(OatFileAssistant::kOatRelocationOutOfDate, oat_file_assistant.OatFileStatus());
EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles());
// Things aren't relocated, so it should fall back to interpreted.
@@ -792,10 +872,8 @@
oat_file_assistant.GetDexOptNeeded(CompilerFilter::kEverything));
EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
- EXPECT_TRUE(oat_file_assistant.OdexFileExists());
EXPECT_EQ(OatFileAssistant::kOatUpToDate, oat_file_assistant.OdexFileStatus());
- EXPECT_FALSE(oat_file_assistant.OatFileExists());
- EXPECT_EQ(OatFileAssistant::kOatOutOfDate, oat_file_assistant.OatFileStatus());
+ EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OatFileStatus());
EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles());
}
@@ -818,10 +896,8 @@
oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
- EXPECT_TRUE(oat_file_assistant.OdexFileExists());
EXPECT_EQ(OatFileAssistant::kOatUpToDate, oat_file_assistant.OdexFileStatus());
- EXPECT_FALSE(oat_file_assistant.OatFileExists());
- EXPECT_EQ(OatFileAssistant::kOatOutOfDate, oat_file_assistant.OatFileStatus());
+ EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OatFileStatus());
EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles());
}
@@ -909,7 +985,7 @@
// Verify it didn't create an oat in the default location.
OatFileAssistant ofm(dex_location.c_str(), kRuntimeISA, false);
- EXPECT_FALSE(ofm.OatFileExists());
+ EXPECT_EQ(OatFileAssistant::kOatCannotOpen, ofm.OatFileStatus());
}
// Case: We have a DEX file but can't write the oat file.
@@ -996,10 +1072,8 @@
EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
EXPECT_EQ(OatFileAssistant::kDex2OatNeeded,
oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
- EXPECT_FALSE(oat_file_assistant.OdexFileExists());
- EXPECT_EQ(OatFileAssistant::kOatOutOfDate, oat_file_assistant.OdexFileStatus());
- EXPECT_FALSE(oat_file_assistant.OatFileExists());
- EXPECT_EQ(OatFileAssistant::kOatOutOfDate, oat_file_assistant.OatFileStatus());
+ EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OdexFileStatus());
+ EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OatFileStatus());
}
// Case: Very short, non-existent Dex location.
@@ -1012,10 +1086,8 @@
EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
- EXPECT_FALSE(oat_file_assistant.OdexFileExists());
- EXPECT_EQ(OatFileAssistant::kOatOutOfDate, oat_file_assistant.OdexFileStatus());
- EXPECT_FALSE(oat_file_assistant.OatFileExists());
- EXPECT_EQ(OatFileAssistant::kOatOutOfDate, oat_file_assistant.OatFileStatus());
+ EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OdexFileStatus());
+ EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OatFileStatus());
EXPECT_FALSE(oat_file_assistant.HasOriginalDexFiles());
// Trying to make it up to date should have no effect.
@@ -1038,10 +1110,8 @@
oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
- EXPECT_FALSE(oat_file_assistant.OdexFileExists());
- EXPECT_EQ(OatFileAssistant::kOatOutOfDate, oat_file_assistant.OdexFileStatus());
- EXPECT_FALSE(oat_file_assistant.OatFileExists());
- EXPECT_EQ(OatFileAssistant::kOatOutOfDate, oat_file_assistant.OatFileStatus());
+ EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OdexFileStatus());
+ EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OatFileStatus());
}
// A task to generate a dex location. Used by the RaceToGenerate test.
@@ -1242,9 +1312,6 @@
}
// TODO: More Tests:
-// * Image checksum change is out of date for kIntepretOnly, but not
-// kVerifyAtRuntime. But target of kVerifyAtRuntime still says current
-// kInterpretOnly is out of date.
// * Test class linker falls back to unquickened dex for DexNoOat
// * Test class linker falls back to unquickened dex for MultiDexNoOat
// * Test using secondary isa
@@ -1258,5 +1325,4 @@
// because it's unrelocated and no dex2oat
// * Test unrelocated specific target compilation type can be relocated to
// make it up to date.
-
} // namespace art