Support oat files compiled with partial boot class path.
Test: oat_file_assistant_test
Bug: 119868597
Bug: 122937705
Change-Id: I07c59957983c0ec61ade5215bb83c41e7cb4b672
diff --git a/runtime/oat_file_assistant.cc b/runtime/oat_file_assistant.cc
index 8b81bb9..80ac01f 100644
--- a/runtime/oat_file_assistant.cc
+++ b/runtime/oat_file_assistant.cc
@@ -563,8 +563,17 @@
bool OatFileAssistant::ImageInfo::ValidateBootClassPathChecksums(const OatFile& oat_file) const {
const char* oat_boot_class_path_checksums =
oat_file.GetOatHeader().GetStoreValueByKey(OatHeader::kBootClassPathChecksumsKey);
- return oat_boot_class_path_checksums != nullptr &&
- oat_boot_class_path_checksums == boot_class_path_checksums;
+ if (oat_boot_class_path_checksums == nullptr) {
+ return false;
+ }
+ // The checksums can be either the same or a prefix of the expected checksums,
+ // ending before the ':' delimiter.
+ size_t length = strlen(oat_boot_class_path_checksums);
+ if (length > boot_class_path_checksums.length() ||
+ (length < boot_class_path_checksums.length() && boot_class_path_checksums[length] != ':')) {
+ return false;
+ }
+ return boot_class_path_checksums.compare(0u, length, oat_boot_class_path_checksums) == 0;
}
std::unique_ptr<OatFileAssistant::ImageInfo>
diff --git a/runtime/oat_file_assistant_test.cc b/runtime/oat_file_assistant_test.cc
index 521e419..a99bd51 100644
--- a/runtime/oat_file_assistant_test.cc
+++ b/runtime/oat_file_assistant_test.cc
@@ -61,6 +61,14 @@
VerifyOptimizationStatus(
file, CompilerFilter::NameOfFilter(expected_filter), expected_reason);
}
+ void InsertNewBootClasspathEntry() {
+ std::string extra_dex_filename = GetMultiDexSrc1();
+ Runtime* runtime = Runtime::Current();
+ runtime->boot_class_path_.push_back(extra_dex_filename);
+ if (!runtime->boot_class_path_locations_.empty()) {
+ runtime->boot_class_path_locations_.push_back(extra_dex_filename);
+ }
+ }
};
class ScopedNonWritable {
@@ -236,17 +244,50 @@
Copy(GetDexSrc1(), dex_location);
GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kSpeed, "install");
- // For the use of oat location by making the dex parent not writable.
- OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
+ // Force the use of oat location by making the dex parent not writable.
+ OatFileAssistant oat_file_assistant(
+ dex_location.c_str(), kRuntimeISA, /*load_executable=*/ false);
EXPECT_EQ(-OatFileAssistant::kNoDexOptNeeded,
- oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
+ oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
EXPECT_EQ(-OatFileAssistant::kNoDexOptNeeded,
- oat_file_assistant.GetDexOptNeeded(CompilerFilter::kQuicken));
+ oat_file_assistant.GetDexOptNeeded(CompilerFilter::kQuicken));
EXPECT_EQ(-OatFileAssistant::kNoDexOptNeeded,
- oat_file_assistant.GetDexOptNeeded(CompilerFilter::kExtract));
+ oat_file_assistant.GetDexOptNeeded(CompilerFilter::kExtract));
EXPECT_EQ(-OatFileAssistant::kDex2OatForFilter,
- oat_file_assistant.GetDexOptNeeded(CompilerFilter::kEverything));
+ oat_file_assistant.GetDexOptNeeded(CompilerFilter::kEverything));
+
+ EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
+ EXPECT_EQ(OatFileAssistant::kOatUpToDate, oat_file_assistant.OdexFileStatus());
+ EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OatFileStatus());
+ EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles());
+
+ VerifyOptimizationStatus(dex_location, CompilerFilter::kSpeed, "install");
+}
+
+// Case: We have an ODEX file compiled against partial boot image.
+// Expect: The status is kNoDexOptNeeded.
+TEST_F(OatFileAssistantTest, OdexUpToDatePartialBootImage) {
+ std::string dex_location = GetScratchDir() + "/OdexUpToDate.jar";
+ std::string odex_location = GetOdexDir() + "/OdexUpToDate.odex";
+ Copy(GetDexSrc1(), dex_location);
+ GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kSpeed, "install");
+
+ // Insert an extra dex file to the boot class path.
+ InsertNewBootClasspathEntry();
+
+ // Force the use of oat location by making the dex parent not writable.
+ OatFileAssistant oat_file_assistant(
+ dex_location.c_str(), kRuntimeISA, /*load_executable=*/ false);
+
+ EXPECT_EQ(-OatFileAssistant::kNoDexOptNeeded,
+ oat_file_assistant.GetDexOptNeeded(CompilerFilter::kSpeed));
+ EXPECT_EQ(-OatFileAssistant::kNoDexOptNeeded,
+ oat_file_assistant.GetDexOptNeeded(CompilerFilter::kQuicken));
+ EXPECT_EQ(-OatFileAssistant::kNoDexOptNeeded,
+ oat_file_assistant.GetDexOptNeeded(CompilerFilter::kExtract));
+ EXPECT_EQ(-OatFileAssistant::kDex2OatForFilter,
+ oat_file_assistant.GetDexOptNeeded(CompilerFilter::kEverything));
EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
EXPECT_EQ(OatFileAssistant::kOatUpToDate, oat_file_assistant.OdexFileStatus());
@@ -302,7 +343,7 @@
Copy(GetDexSrc1(), dex_location);
GenerateOatForTest(dex_location.c_str(), CompilerFilter::kSpeed);
- // For the use of oat location by making the dex parent not writable.
+ // Force the use of oat location by making the dex parent not writable.
ScopedNonWritable scoped_non_writable(dex_location);
ASSERT_TRUE(scoped_non_writable.IsSuccessful());
diff --git a/runtime/runtime.h b/runtime/runtime.h
index 1acb75b..1d1d0d3 100644
--- a/runtime/runtime.h
+++ b/runtime/runtime.h
@@ -91,6 +91,7 @@
class MonitorList;
class MonitorPool;
class NullPointerHandler;
+class OatFileAssistantTest;
class OatFileManager;
class Plugin;
struct RuntimeArgumentMap;
@@ -1145,6 +1146,7 @@
// Note: See comments on GetFaultMessage.
friend std::string GetFaultMessageForAbortLogging();
friend class ScopedThreadPoolUsage;
+ friend class OatFileAssistantTest;
DISALLOW_COPY_AND_ASSIGN(Runtime);
};