summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--compiler/driver/compiler_options.h4
-rw-r--r--dex2oat/dex2oat.cc11
-rw-r--r--runtime/oat.cc4
-rw-r--r--runtime/oat.h2
-rw-r--r--runtime/oat_file.cc4
-rw-r--r--runtime/oat_file.h2
-rw-r--r--runtime/oat_file_assistant.cc22
-rw-r--r--runtime/oat_file_assistant_test.cc71
8 files changed, 118 insertions, 2 deletions
diff --git a/compiler/driver/compiler_options.h b/compiler/driver/compiler_options.h
index 39372b36b8..a220959288 100644
--- a/compiler/driver/compiler_options.h
+++ b/compiler/driver/compiler_options.h
@@ -116,6 +116,10 @@ class CompilerOptions FINAL {
return compiler_filter_ == CompilerOptions::kVerifyNone;
}
+ bool IsExtractOnly() const {
+ return compiler_filter_ == CompilerOptions::kVerifyAtRuntime;
+ }
+
size_t GetHugeMethodThreshold() const {
return huge_method_threshold_;
}
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index 48716481cc..8e80961e43 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -1055,6 +1055,9 @@ class Dex2Oat FINAL {
key_value_store_->Put(
OatHeader::kDebuggableKey,
compiler_options_->debuggable_ ? OatHeader::kTrueValue : OatHeader::kFalseValue);
+ key_value_store_->Put(
+ OatHeader::kExtractOnlyKey,
+ compiler_options_->IsExtractOnly() ? OatHeader::kTrueValue : OatHeader::kFalseValue);
}
// Parse the arguments from the command line. In case of an unrecognized option or impossible
@@ -1332,7 +1335,13 @@ class Dex2Oat FINAL {
return false;
}
- {
+ if (compiler_options_->IsExtractOnly()) {
+ // ExtractOnly oat files only contain non-quickened DEX code and are
+ // therefore independent of the image file.
+ image_file_location_oat_checksum_ = 0u;
+ image_file_location_oat_data_begin_ = 0u;
+ image_patch_delta_ = 0;
+ } else {
TimingLogger::ScopedTiming t3("Loading image checksum", timings_);
std::vector<gc::space::ImageSpace*> image_spaces =
Runtime::Current()->GetHeap()->GetBootImageSpaces();
diff --git a/runtime/oat.cc b/runtime/oat.cc
index c787b9adb1..4948558f84 100644
--- a/runtime/oat.cc
+++ b/runtime/oat.cc
@@ -466,6 +466,10 @@ bool OatHeader::IsDebuggable() const {
return IsKeyEnabled(OatHeader::kDebuggableKey);
}
+bool OatHeader::IsExtractOnly() const {
+ return IsKeyEnabled(OatHeader::kExtractOnlyKey);
+}
+
bool OatHeader::IsKeyEnabled(const char* key) const {
const char* key_value = GetStoreValueByKey(key);
return (key_value != nullptr && strncmp(key_value, kTrueValue, sizeof(kTrueValue)) == 0);
diff --git a/runtime/oat.h b/runtime/oat.h
index 989e3f9d89..fde386f37e 100644
--- a/runtime/oat.h
+++ b/runtime/oat.h
@@ -38,6 +38,7 @@ class PACKED(4) OatHeader {
static constexpr const char* kDex2OatHostKey = "dex2oat-host";
static constexpr const char* kPicKey = "pic";
static constexpr const char* kDebuggableKey = "debuggable";
+ static constexpr const char* kExtractOnlyKey = "extract-only";
static constexpr const char* kClassPathKey = "classpath";
static constexpr const char* kBootClassPath = "bootclasspath";
@@ -106,6 +107,7 @@ class PACKED(4) OatHeader {
size_t GetHeaderSize() const;
bool IsPic() const;
bool IsDebuggable() const;
+ bool IsExtractOnly() const;
private:
OatHeader(InstructionSet instruction_set,
diff --git a/runtime/oat_file.cc b/runtime/oat_file.cc
index 8f321a092c..f912598eef 100644
--- a/runtime/oat_file.cc
+++ b/runtime/oat_file.cc
@@ -1221,6 +1221,10 @@ bool OatFile::IsDebuggable() const {
return GetOatHeader().IsDebuggable();
}
+bool OatFile::IsExtractOnly() const {
+ return GetOatHeader().IsExtractOnly();
+}
+
static constexpr char kDexClassPathEncodingSeparator = '*';
std::string OatFile::EncodeDexFileDependencies(const std::vector<const DexFile*>& dex_files) {
diff --git a/runtime/oat_file.h b/runtime/oat_file.h
index dbd75415a4..bcc2d33333 100644
--- a/runtime/oat_file.h
+++ b/runtime/oat_file.h
@@ -85,6 +85,8 @@ class OatFile {
// Indicates whether the oat file was compiled with full debugging capability.
bool IsDebuggable() const;
+ bool IsExtractOnly() const;
+
const std::string& GetLocation() const {
return location_;
}
diff --git a/runtime/oat_file_assistant.cc b/runtime/oat_file_assistant.cc
index a8f84a2bfa..6daade0648 100644
--- a/runtime/oat_file_assistant.cc
+++ b/runtime/oat_file_assistant.cc
@@ -461,6 +461,23 @@ bool OatFileAssistant::GivenOatFileIsOutOfDate(const OatFile& file) {
}
}
+ if (file.IsExtractOnly()) {
+ VLOG(oat) << "Oat file is extract-only. Image checksum test skipped.";
+ if (kIsDebugBuild) {
+ // Sanity check that no classes have compiled code. Does not test that
+ // the DEX code has not been quickened.
+ std::string error_msg;
+ for (const OatFile::OatDexFile* current : file.GetOatDexFiles()) {
+ const DexFile* const dex_file = current->OpenDexFile(&error_msg).release();
+ DCHECK(dex_file != nullptr);
+ for (size_t i = 0, e = dex_file->NumClassDefs(); i < e; ++i) {
+ DCHECK_EQ(current->GetOatClass(i).GetType(), kOatClassNoneCompiled);
+ }
+ }
+ }
+ return false;
+ }
+
// Verify the image checksum
const ImageInfo* image_info = GetImageInfo();
if (image_info == nullptr) {
@@ -486,7 +503,10 @@ bool OatFileAssistant::GivenOatFileIsUpToDate(const OatFile& file) {
return false;
}
- if (file.IsPic()) {
+ if (file.IsPic() || file.IsExtractOnly()) {
+ // Oat files compiled in PIC mode do not require relocation and extract-only
+ // oat files do not contain any compiled code. Skip the relocation test.
+ VLOG(oat) << "Oat relocation test skipped.";
return true;
}
diff --git a/runtime/oat_file_assistant_test.cc b/runtime/oat_file_assistant_test.cc
index 25dcbe4c63..83d4457a1c 100644
--- a/runtime/oat_file_assistant_test.cc
+++ b/runtime/oat_file_assistant_test.cc
@@ -259,6 +259,26 @@ class OatFileAssistantTest : public CommonRuntimeTest {
EXPECT_TRUE(odex_file->IsPic());
}
+ void GenerateExtractOnlyOdexForTest(const std::string& dex_location,
+ const std::string& odex_location) {
+ std::vector<std::string> args;
+ args.push_back("--dex-file=" + dex_location);
+ args.push_back("--oat-file=" + odex_location);
+ args.push_back("--compiler-filter=verify-at-runtime");
+ std::string error_msg;
+ ASSERT_TRUE(OatFileAssistant::Dex2Oat(args, &error_msg)) << error_msg;
+
+ // Verify the odex file was generated as expected.
+ std::unique_ptr<OatFile> odex_file(OatFile::Open(
+ odex_location.c_str(), odex_location.c_str(), nullptr, nullptr,
+ false, dex_location.c_str(), &error_msg));
+ ASSERT_TRUE(odex_file.get() != nullptr) << error_msg;
+ EXPECT_TRUE(odex_file->IsExtractOnly());
+ EXPECT_EQ(odex_file->GetOatHeader().GetImageFileLocationOatChecksum(), 0u);
+ EXPECT_EQ(odex_file->GetOatHeader().GetImageFileLocationOatDataBegin(), 0u);
+ EXPECT_EQ(odex_file->GetOatHeader().GetImagePatchDelta(), 0);
+}
+
private:
// Reserve memory around where the image will be loaded so other memory
// won't conflict when it comes time to load the image.
@@ -488,6 +508,32 @@ TEST_F(OatFileAssistantTest, OatOutOfDate) {
EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles());
}
+// Case: We have a DEX file and an extract-only ODEX file out of date relative
+// to the DEX file.
+// Expect: The status is kDex2OatNeeded.
+TEST_F(OatFileAssistantTest, ExtractOnlyOdexOutOfDate) {
+ std::string dex_location = GetScratchDir() + "/ExtractOnlyOdexOutOfDate.jar";
+ std::string odex_location = GetOdexDir() + "/ExtractOnlyOdexOutOfDate.odex";
+
+ // We create a dex, generate an oat for it, then overwrite the dex with a
+ // different dex to make the oat out of date.
+ Copy(GetDexSrc1(), dex_location);
+ GenerateExtractOnlyOdexForTest(dex_location.c_str(), odex_location.c_str());
+ Copy(GetDexSrc2(), dex_location);
+
+ OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
+ EXPECT_EQ(OatFileAssistant::kDex2OatNeeded, oat_file_assistant.GetDexOptNeeded());
+
+ EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
+ EXPECT_TRUE(oat_file_assistant.OdexFileExists());
+ EXPECT_TRUE(oat_file_assistant.OdexFileIsOutOfDate());
+ EXPECT_FALSE(oat_file_assistant.OdexFileIsUpToDate());
+ EXPECT_FALSE(oat_file_assistant.OatFileExists());
+ EXPECT_TRUE(oat_file_assistant.OatFileIsOutOfDate());
+ EXPECT_FALSE(oat_file_assistant.OatFileIsUpToDate());
+ EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles());
+}
+
// Case: We have a DEX file and an ODEX file, but no OAT file.
// Expect: The status is kPatchOatNeeded.
TEST_F(OatFileAssistantTest, DexOdexNoOat) {
@@ -784,6 +830,31 @@ TEST_F(OatFileAssistantTest, DexPicOdexNoOat) {
EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles());
}
+// Case: We have a DEX file and a ExtractOnly ODEX file, but no OAT file.
+// Expect: The status is kNoDexOptNeeded, because ExtractOnly contains no code.
+TEST_F(OatFileAssistantTest, DexExtractOnlyOdexNoOat) {
+ std::string dex_location = GetScratchDir() + "/DexExtractOnlyOdexNoOat.jar";
+ std::string odex_location = GetOdexDir() + "/DexExtractOnlyOdexNoOat.odex";
+
+ // Create the dex and odex files
+ Copy(GetDexSrc1(), dex_location);
+ GenerateExtractOnlyOdexForTest(dex_location, odex_location);
+
+ // Verify the status.
+ OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
+
+ EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded, oat_file_assistant.GetDexOptNeeded());
+
+ EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
+ EXPECT_TRUE(oat_file_assistant.OdexFileExists());
+ EXPECT_FALSE(oat_file_assistant.OdexFileIsOutOfDate());
+ EXPECT_TRUE(oat_file_assistant.OdexFileIsUpToDate());
+ EXPECT_FALSE(oat_file_assistant.OatFileExists());
+ EXPECT_TRUE(oat_file_assistant.OatFileIsOutOfDate());
+ EXPECT_FALSE(oat_file_assistant.OatFileIsUpToDate());
+ EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles());
+}
+
// Case: We have a DEX file and up-to-date OAT file for it.
// Expect: We should load an executable dex file.
TEST_F(OatFileAssistantTest, LoadOatUpToDate) {