Rewrite OatFileManager::OpenDexFilesFromOat.
- Remove obsolete option -Xno-dex-file-fallback
- Only load an oat file when class loader context matches.
- Remove obsolete duplicate class check code.
Bug: 132357300
Bug: 156250899
Change-Id: I78e645806e0de2f35ce2614285f1a7cbc705484c
diff --git a/runtime/oat_file_assistant.cc b/runtime/oat_file_assistant.cc
index f374883..9c169e6 100644
--- a/runtime/oat_file_assistant.cc
+++ b/runtime/oat_file_assistant.cc
@@ -305,8 +305,8 @@
return true;
}
-bool OatFileAssistant::HasOriginalDexFiles() {
- ScopedTrace trace("HasOriginalDexFiles");
+bool OatFileAssistant::HasDexFiles() {
+ ScopedTrace trace("HasDexFiles");
// Ensure GetRequiredDexChecksums has been run so that
// has_original_dex_files_ is initialized. We don't care about the result of
// GetRequiredDexChecksums.
@@ -633,20 +633,7 @@
if (!result) {
VLOG(oat) << "Failed to verify checksums of oat file " << oat_file.GetLocation()
<< " error: " << error_msg;
-
- if (HasOriginalDexFiles()) {
- return false;
- }
-
- // If there is no original dex file to fall back to, grudgingly accept
- // the oat file. This could technically lead to crashes, but there's no
- // way we could find a better oat file to use for this dex location,
- // and it's better than being stuck in a boot loop with no way out.
- // The problem will hopefully resolve itself the next time the runtime
- // starts up.
- LOG(WARNING) << "Dex location " << dex_location_ << " does not seem to include dex file. "
- << "Allow oat file use. This is potentially dangerous.";
- return true;
+ return false;
}
// This checksum has been validated, so save it.
@@ -683,13 +670,6 @@
return odex_;
}
- // The oat file is not usable and the odex file is not up to date.
- // However we have access to the original dex file which means we can make
- // the oat location up to date.
- if (HasOriginalDexFiles()) {
- return oat_;
- }
-
// We got into the worst situation here:
// - the oat location is not usable
// - the prebuild odex location is not up to date
@@ -822,10 +802,10 @@
}
}
- if (oat_file_assistant_->HasOriginalDexFiles()) {
+ if (oat_file_assistant_->HasDexFiles()) {
return kDex2OatFromScratch;
} else {
- // Otherwise there is nothing we can do, even if we want to.
+ // No dex file, there is nothing we need to do.
return kNoDexOptNeeded;
}
}
@@ -969,27 +949,6 @@
return ReleaseFile();
}
- VLOG(oat) << "Oat File Assistant: No relocated oat file found,"
- << " attempting to fall back to interpreting oat file instead.";
-
- switch (Status()) {
- case kOatBootImageOutOfDate:
- // OutOfDate may be either a mismatched image, or a missing image.
- if (oat_file_assistant_->HasOriginalDexFiles()) {
- // If there are original dex files, it is better to use them (to avoid a potential
- // quickening mismatch because the boot image changed).
- break;
- }
- // If we do not accept the oat file, we may not have access to dex bytecode at all. Grudgingly
- // go forward.
- FALLTHROUGH_INTENDED;
-
- case kOatUpToDate:
- case kOatCannotOpen:
- case kOatDexOutOfDate:
- break;
- }
-
return std::unique_ptr<OatFile>();
}
@@ -1030,11 +989,8 @@
case kOatBootImageOutOfDate:
FALLTHROUGH_INTENDED;
case kOatDexOutOfDate:
- if (oat_file_assistant.HasOriginalDexFiles()) {
- *out_compilation_filter = "run-from-apk-fallback";
- } else {
- *out_compilation_filter = "run-from-vdex-fallback";
- }
+ DCHECK(oat_file_assistant.HasDexFiles());
+ *out_compilation_filter = "run-from-apk-fallback";
return;
}
LOG(FATAL) << "Unreachable";
diff --git a/runtime/oat_file_assistant.h b/runtime/oat_file_assistant.h
index aa4d83b..069e6fa 100644
--- a/runtime/oat_file_assistant.h
+++ b/runtime/oat_file_assistant.h
@@ -200,11 +200,8 @@
const std::string& dex_location,
std::vector<std::unique_ptr<const DexFile>>* out_dex_files);
- // Returns true if there are dex files in the original dex location that can
- // be compiled with dex2oat for this dex location.
- // Returns false if there is no original dex file, or if the original dex
- // file is an apk/zip without a classes.dex entry.
- bool HasOriginalDexFiles();
+ // Returns whether this is an apk/zip wit a classes.dex entry.
+ bool HasDexFiles();
// If the dex file has been installed with a compiled oat file alongside
// it, the compiled oat file will have the extension .odex, and is referred
diff --git a/runtime/oat_file_assistant_test.cc b/runtime/oat_file_assistant_test.cc
index 7b1a5eb..92347b1 100644
--- a/runtime/oat_file_assistant_test.cc
+++ b/runtime/oat_file_assistant_test.cc
@@ -242,7 +242,7 @@
EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OdexFileStatus());
EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OatFileStatus());
- EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles());
+ EXPECT_TRUE(oat_file_assistant.HasDexFiles());
VerifyOptimizationStatus(dex_location, "run-from-apk", "unknown");
}
@@ -256,7 +256,7 @@
EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kSpeed));
- EXPECT_FALSE(oat_file_assistant.HasOriginalDexFiles());
+ EXPECT_FALSE(oat_file_assistant.HasDexFiles());
// Trying to get the best oat file should fail, but not crash.
std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
@@ -287,7 +287,7 @@
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());
+ EXPECT_TRUE(oat_file_assistant.HasDexFiles());
VerifyOptimizationStatus(dex_location, CompilerFilter::kSpeed, "install");
}
@@ -319,7 +319,7 @@
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());
+ EXPECT_TRUE(oat_file_assistant.HasDexFiles());
VerifyOptimizationStatus(dex_location, CompilerFilter::kSpeed, "install");
}
@@ -354,7 +354,7 @@
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());
+ EXPECT_TRUE(oat_file_assistant.HasDexFiles());
}
// Case: We have a DEX file and up-to-date OAT file for it.
@@ -388,7 +388,7 @@
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());
+ EXPECT_TRUE(oat_file_assistant.HasDexFiles());
VerifyOptimizationStatus(dex_location, CompilerFilter::kSpeed, "unknown");
}
@@ -429,7 +429,7 @@
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());
+ EXPECT_TRUE(oat_file_assistant.HasDexFiles());
}
// Case: Passing invalid odex fd and valid vdex and zip fds.
@@ -463,7 +463,7 @@
EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
EXPECT_EQ(OatFileAssistant::kOatBootImageOutOfDate, oat_file_assistant.OdexFileStatus());
EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OatFileStatus());
- EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles());
+ EXPECT_TRUE(oat_file_assistant.HasDexFiles());
}
// Case: Passing invalid vdex fd and valid odex and zip fds.
@@ -494,7 +494,7 @@
EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OdexFileStatus());
EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OatFileStatus());
- EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles());
+ EXPECT_TRUE(oat_file_assistant.HasDexFiles());
}
// Case: Passing invalid vdex and odex fd with valid zip fd.
@@ -626,7 +626,7 @@
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());
+ EXPECT_TRUE(oat_file_assistant.HasDexFiles());
}
// Case: We have a MultiDEX file and up-to-date OAT file for it.
@@ -648,7 +648,7 @@
OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kSpeed));
- EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles());
+ EXPECT_TRUE(oat_file_assistant.HasDexFiles());
// Verify we can load both dex files.
std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
@@ -684,38 +684,7 @@
OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
EXPECT_EQ(OatFileAssistant::kDex2OatFromScratch,
GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kSpeed));
- EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles());
-}
-
-// Case: We have a stripped MultiDEX file where the non-main multidex entry is
-// out of date with respect to the odex file.
-TEST_F(OatFileAssistantTest, StrippedMultiDexNonMainOutOfDate) {
- std::string dex_location = GetScratchDir() + "/StrippedMultiDexNonMainOutOfDate.jar";
- std::string odex_location = GetOdexDir() + "/StrippedMultiDexNonMainOutOfDate.odex";
-
- // Compile the oat from GetMultiDexSrc1.
- Copy(GetMultiDexSrc1(), dex_location);
- GenerateOatForTest(dex_location.c_str(), CompilerFilter::kSpeed);
-
- // Compile the odex from GetMultiDexSrc2, which has a different non-main
- // dex checksum.
- Copy(GetMultiDexSrc2(), dex_location);
- GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kQuicken);
-
- // Strip the dex file.
- Copy(GetStrippedDexSrc1(), dex_location);
-
- OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, /*load_executable=*/false);
-
- // Because the dex file is stripped, the odex file is considered the source
- // of truth for the dex checksums. The oat file should be considered
- // unusable.
- std::unique_ptr<OatFile> best_file = oat_file_assistant.GetBestOatFile();
- ASSERT_TRUE(best_file.get() != nullptr);
- EXPECT_EQ(best_file->GetLocation(), odex_location);
- EXPECT_FALSE(oat_file_assistant.HasOriginalDexFiles());
- EXPECT_EQ(OatFileAssistant::kOatUpToDate, oat_file_assistant.OdexFileStatus());
- EXPECT_EQ(OatFileAssistant::kOatDexOutOfDate, oat_file_assistant.OatFileStatus());
+ EXPECT_TRUE(oat_file_assistant.HasDexFiles());
}
// Case: We have a DEX file and an OAT file out of date with respect to the
@@ -747,7 +716,7 @@
EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OdexFileStatus());
EXPECT_EQ(OatFileAssistant::kOatDexOutOfDate, oat_file_assistant.OatFileStatus());
- EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles());
+ EXPECT_TRUE(oat_file_assistant.HasDexFiles());
}
// Case: We have a DEX file and an (ODEX) VDEX file out of date with respect
@@ -814,7 +783,7 @@
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());
+ EXPECT_TRUE(oat_file_assistant.HasDexFiles());
}
// Case: We have a DEX file and a verify-at-runtime OAT file out of date with
@@ -847,7 +816,7 @@
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());
+ EXPECT_TRUE(oat_file_assistant.HasDexFiles());
}
// Case: We have a DEX file and an ODEX file, but no OAT file.
@@ -870,86 +839,14 @@
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());
+ EXPECT_TRUE(oat_file_assistant.HasDexFiles());
// We should still be able to get the non-executable odex file to run from.
std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
ASSERT_TRUE(oat_file.get() != nullptr);
}
-// Case: We have a stripped DEX file and a PIC ODEX file, but no OAT file.
-TEST_F(OatFileAssistantTest, StrippedDexOdexNoOat) {
- std::string dex_location = GetScratchDir() + "/StrippedDexOdexNoOat.jar";
- std::string odex_location = GetOdexDir() + "/StrippedDexOdexNoOat.odex";
-
- // Create the dex and odex files
- Copy(GetDexSrc1(), dex_location);
- GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kSpeed);
-
- // Strip the dex file
- Copy(GetStrippedDexSrc1(), dex_location);
-
- // Verify the status.
- OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
-
- EXPECT_EQ(-OatFileAssistant::kNoDexOptNeeded,
- GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kSpeed));
-
- EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
- EXPECT_EQ(OatFileAssistant::kOatUpToDate, oat_file_assistant.OdexFileStatus());
- EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OatFileStatus());
- EXPECT_FALSE(oat_file_assistant.HasOriginalDexFiles());
-
- // Verify we can load the dex files from it.
- std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
- ASSERT_TRUE(oat_file.get() != nullptr);
- EXPECT_TRUE(oat_file->IsExecutable());
- std::vector<std::unique_ptr<const DexFile>> dex_files;
- dex_files = oat_file_assistant.LoadDexFiles(*oat_file, dex_location.c_str());
- EXPECT_EQ(1u, dex_files.size());
-}
-
-// Case: We have a stripped DEX file, a PIC ODEX file, and an out-of-date OAT file.
-TEST_F(OatFileAssistantTest, StrippedDexOdexOat) {
- std::string dex_location = GetScratchDir() + "/StrippedDexOdexOat.jar";
- std::string odex_location = GetOdexDir() + "/StrippedDexOdexOat.odex";
-
- // Create the oat file from a different dex file so it looks out of date.
- Copy(GetDexSrc2(), dex_location);
- GenerateOatForTest(dex_location.c_str(), CompilerFilter::kSpeed);
-
- // Create the odex file
- Copy(GetDexSrc1(), dex_location);
- GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kSpeed);
-
- // Strip the dex file.
- Copy(GetStrippedDexSrc1(), dex_location);
-
- // Verify the status.
- OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
-
- EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
- GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kExtract));
- EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
- GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kSpeed));
- EXPECT_EQ(-OatFileAssistant::kDex2OatForFilter, // Compiling from the .vdex file
- GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kEverything));
-
- EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
- EXPECT_EQ(OatFileAssistant::kOatUpToDate, oat_file_assistant.OdexFileStatus());
- EXPECT_EQ(OatFileAssistant::kOatDexOutOfDate, oat_file_assistant.OatFileStatus());
- EXPECT_FALSE(oat_file_assistant.HasOriginalDexFiles());
-
- // Verify we can load the dex files from it.
- std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
- ASSERT_TRUE(oat_file.get() != nullptr);
- EXPECT_TRUE(oat_file->IsExecutable());
- std::vector<std::unique_ptr<const DexFile>> dex_files;
- dex_files = oat_file_assistant.LoadDexFiles(*oat_file, dex_location.c_str());
- EXPECT_EQ(1u, dex_files.size());
-}
-
-// Case: We have a stripped (or resource-only) DEX file, no ODEX file and no
+// Case: We have a resource-only DEX file, no ODEX file and no
// OAT file. Expect: The status is kNoDexOptNeeded.
TEST_F(OatFileAssistantTest, ResourceOnlyDex) {
std::string dex_location = GetScratchDir() + "/ResourceOnlyDex.jar";
@@ -969,7 +866,7 @@
EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OdexFileStatus());
EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OatFileStatus());
- EXPECT_FALSE(oat_file_assistant.HasOriginalDexFiles());
+ EXPECT_FALSE(oat_file_assistant.HasDexFiles());
EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kSpeed));
@@ -977,7 +874,7 @@
EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OdexFileStatus());
EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OatFileStatus());
- EXPECT_FALSE(oat_file_assistant.HasOriginalDexFiles());
+ EXPECT_FALSE(oat_file_assistant.HasDexFiles());
}
// Case: We have a DEX file, an ODEX file and an OAT file.
@@ -1000,7 +897,7 @@
EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
EXPECT_EQ(OatFileAssistant::kOatUpToDate, oat_file_assistant.OdexFileStatus());
EXPECT_EQ(OatFileAssistant::kOatUpToDate, oat_file_assistant.OatFileStatus());
- EXPECT_TRUE(oat_file_assistant.HasOriginalDexFiles());
+ EXPECT_TRUE(oat_file_assistant.HasDexFiles());
std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
ASSERT_TRUE(oat_file.get() != nullptr);
@@ -1032,7 +929,7 @@
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());
+ EXPECT_TRUE(oat_file_assistant.HasDexFiles());
}
// Case: We have a DEX file and up-to-date OAT file for it.
@@ -1184,7 +1081,7 @@
GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kSpeed));
EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OdexFileStatus());
EXPECT_EQ(OatFileAssistant::kOatCannotOpen, oat_file_assistant.OatFileStatus());
- EXPECT_FALSE(oat_file_assistant.HasOriginalDexFiles());
+ EXPECT_FALSE(oat_file_assistant.HasDexFiles());
}
// Case: Non-standard extension for dex file.
@@ -1589,7 +1486,7 @@
&error_msgs);
EXPECT_FALSE(dex_files.empty());
- EXPECT_NE(oat_file, nullptr);
+ ASSERT_NE(oat_file, nullptr);
EXPECT_FALSE(oat_file->IsExecutable());
}
diff --git a/runtime/oat_file_manager.cc b/runtime/oat_file_manager.cc
index 29c130d..85992ea 100644
--- a/runtime/oat_file_manager.cc
+++ b/runtime/oat_file_manager.cc
@@ -169,234 +169,19 @@
return oat_files;
}
-class TypeIndexInfo {
- public:
- explicit TypeIndexInfo(const DexFile* dex_file)
- : type_indexes_(GenerateTypeIndexes(dex_file)),
- iter_(type_indexes_.Indexes().begin()),
- end_(type_indexes_.Indexes().end()) { }
-
- BitVector& GetTypeIndexes() {
- return type_indexes_;
- }
- BitVector::IndexIterator& GetIterator() {
- return iter_;
- }
- BitVector::IndexIterator& GetIteratorEnd() {
- return end_;
- }
- void AdvanceIterator() {
- iter_++;
- }
-
- private:
- static BitVector GenerateTypeIndexes(const DexFile* dex_file) {
- BitVector type_indexes(/*start_bits=*/0, /*expandable=*/true, Allocator::GetMallocAllocator());
- for (uint16_t i = 0; i < dex_file->NumClassDefs(); ++i) {
- const dex::ClassDef& class_def = dex_file->GetClassDef(i);
- uint16_t type_idx = class_def.class_idx_.index_;
- type_indexes.SetBit(type_idx);
- }
- return type_indexes;
- }
-
- // BitVector with bits set for the type indexes of all classes in the input dex file.
- BitVector type_indexes_;
- BitVector::IndexIterator iter_;
- BitVector::IndexIterator end_;
-};
-
-class DexFileAndClassPair : ValueObject {
- public:
- DexFileAndClassPair(const DexFile* dex_file, TypeIndexInfo* type_info, bool from_loaded_oat)
- : type_info_(type_info),
- dex_file_(dex_file),
- cached_descriptor_(dex_file_->StringByTypeIdx(dex::TypeIndex(*type_info->GetIterator()))),
- from_loaded_oat_(from_loaded_oat) {
- type_info_->AdvanceIterator();
- }
-
- DexFileAndClassPair(const DexFileAndClassPair& rhs) = default;
-
- DexFileAndClassPair& operator=(const DexFileAndClassPair& rhs) = default;
-
- const char* GetCachedDescriptor() const {
- return cached_descriptor_;
- }
-
- bool operator<(const DexFileAndClassPair& rhs) const {
- const int cmp = strcmp(cached_descriptor_, rhs.cached_descriptor_);
- if (cmp != 0) {
- // Note that the order must be reversed. We want to iterate over the classes in dex files.
- // They are sorted lexicographically. Thus, the priority-queue must be a min-queue.
- return cmp > 0;
- }
- return dex_file_ < rhs.dex_file_;
- }
-
- bool DexFileHasMoreClasses() const {
- return type_info_->GetIterator() != type_info_->GetIteratorEnd();
- }
-
- void Next() {
- cached_descriptor_ = dex_file_->StringByTypeIdx(dex::TypeIndex(*type_info_->GetIterator()));
- type_info_->AdvanceIterator();
- }
-
- bool FromLoadedOat() const {
- return from_loaded_oat_;
- }
-
- const DexFile* GetDexFile() const {
- return dex_file_;
- }
-
- private:
- TypeIndexInfo* type_info_;
- const DexFile* dex_file_;
- const char* cached_descriptor_;
- bool from_loaded_oat_; // We only need to compare mismatches between what we load now
- // and what was loaded before. Any old duplicates must have been
- // OK, and any new "internal" duplicates are as well (they must
- // be from multidex, which resolves correctly).
-};
-
-static void AddDexFilesFromOat(
- const OatFile* oat_file,
- /*out*/std::vector<const DexFile*>* dex_files,
- std::vector<std::unique_ptr<const DexFile>>* opened_dex_files) {
- for (const OatDexFile* oat_dex_file : oat_file->GetOatDexFiles()) {
- std::string error;
- std::unique_ptr<const DexFile> dex_file = oat_dex_file->OpenDexFile(&error);
- if (dex_file == nullptr) {
- LOG(WARNING) << "Could not create dex file from oat file: " << error;
- } else if (dex_file->NumClassDefs() > 0U) {
- dex_files->push_back(dex_file.get());
- opened_dex_files->push_back(std::move(dex_file));
- }
- }
-}
-
-static void AddNext(/*inout*/DexFileAndClassPair& original,
- /*inout*/std::priority_queue<DexFileAndClassPair>& heap) {
- if (original.DexFileHasMoreClasses()) {
- original.Next();
- heap.push(std::move(original));
- }
-}
-
-static bool CheckClassCollision(const OatFile* oat_file,
- const ClassLoaderContext* context,
- std::string* error_msg /*out*/) {
- std::vector<const DexFile*> dex_files_loaded = context->FlattenOpenedDexFiles();
-
- // Vector that holds the newly opened dex files live, this is done to prevent leaks.
- std::vector<std::unique_ptr<const DexFile>> opened_dex_files;
-
- ScopedTrace st("Collision check");
- // Add dex files from the oat file to check.
- std::vector<const DexFile*> dex_files_unloaded;
- AddDexFilesFromOat(oat_file, &dex_files_unloaded, &opened_dex_files);
-
- // Generate type index information for each dex file.
- std::vector<TypeIndexInfo> loaded_types;
- loaded_types.reserve(dex_files_loaded.size());
- for (const DexFile* dex_file : dex_files_loaded) {
- loaded_types.push_back(TypeIndexInfo(dex_file));
- }
- std::vector<TypeIndexInfo> unloaded_types;
- unloaded_types.reserve(dex_files_unloaded.size());
- for (const DexFile* dex_file : dex_files_unloaded) {
- unloaded_types.push_back(TypeIndexInfo(dex_file));
- }
-
- // Populate the queue of dex file and class pairs with the loaded and unloaded dex files.
- std::priority_queue<DexFileAndClassPair> queue;
- for (size_t i = 0; i < dex_files_loaded.size(); ++i) {
- if (loaded_types[i].GetIterator() != loaded_types[i].GetIteratorEnd()) {
- queue.emplace(dex_files_loaded[i], &loaded_types[i], /*from_loaded_oat=*/true);
- }
- }
- for (size_t i = 0; i < dex_files_unloaded.size(); ++i) {
- if (unloaded_types[i].GetIterator() != unloaded_types[i].GetIteratorEnd()) {
- queue.emplace(dex_files_unloaded[i], &unloaded_types[i], /*from_loaded_oat=*/false);
- }
- }
-
- // Now drain the queue.
- bool has_duplicates = false;
- error_msg->clear();
- while (!queue.empty()) {
- // Modifying the top element is only safe if we pop right after.
- DexFileAndClassPair compare_pop(queue.top());
- queue.pop();
-
- // Compare against the following elements.
- while (!queue.empty()) {
- DexFileAndClassPair top(queue.top());
- if (strcmp(compare_pop.GetCachedDescriptor(), top.GetCachedDescriptor()) == 0) {
- // Same descriptor. Check whether it's crossing old-oat-files to new-oat-files.
- if (compare_pop.FromLoadedOat() != top.FromLoadedOat()) {
- error_msg->append(
- StringPrintf("Found duplicated class when checking oat files: '%s' in %s and %s\n",
- compare_pop.GetCachedDescriptor(),
- compare_pop.GetDexFile()->GetLocation().c_str(),
- top.GetDexFile()->GetLocation().c_str()));
- if (!VLOG_IS_ON(oat)) {
- return true;
- }
- has_duplicates = true;
- }
- queue.pop();
- AddNext(top, queue);
- } else {
- // Something else. Done here.
- break;
- }
- }
- AddNext(compare_pop, queue);
- }
-
- return has_duplicates;
-}
-
-// Check for class-def collisions in dex files.
-//
-// This first walks the class loader chain present in the given context, getting all the dex files
-// from the class loader.
-//
-// If the context is null (which means the initial class loader was null or unsupported)
-// this returns false. b/37777332.
-//
-// This first checks whether all class loaders in the context have the same type and
-// classpath. If so, we exit early. Otherwise, we do the collision check.
-//
-// The collision check works by maintaining a heap with one class from each dex file, sorted by the
-// class descriptor. Then a dex-file/class pair is continually removed from the heap and compared
-// against the following top element. If the descriptor is the same, it is now checked whether
-// the two elements agree on whether their dex file was from an already-loaded oat-file or the
-// new oat file. Any disagreement indicates a collision.
-OatFileManager::CheckCollisionResult OatFileManager::CheckCollision(
+static bool ClassLoaderContextMatches(
const OatFile* oat_file,
const ClassLoaderContext* context,
- /*out*/ std::string* error_msg) const {
+ bool* is_special_shared_library,
+ /*out*/ std::string* error_msg) {
DCHECK(oat_file != nullptr);
DCHECK(error_msg != nullptr);
-
- // The context might be null if there are unrecognized class loaders in the chain or they
- // don't meet sensible sanity conditions. In this case we assume that the app knows what it's
- // doing and accept the oat file.
- // Note that this has correctness implications as we cannot guarantee that the class resolution
- // used during compilation is OK (b/37777332).
- if (context == nullptr) {
- LOG(WARNING) << "Skipping duplicate class check due to unsupported classloader";
- return CheckCollisionResult::kSkippedUnsupportedClassLoader;
- }
+ DCHECK(context != nullptr);
if (!CompilerFilter::IsVerificationEnabled(oat_file->GetCompilerFilter())) {
- // If verification is not enabled we don't need to check for collisions as the oat file
- // is either extracted or assumed verified.
- return CheckCollisionResult::kSkippedVerificationDisabled;
+ // If verification is not enabled we don't need to check if class loader context matches
+ // as the oat file is either extracted or assumed verified.
+ return true;
}
// If the oat file loading context matches the context used during compilation then we accept
@@ -407,48 +192,21 @@
/*verify_checksums=*/ true);
switch (result) {
case ClassLoaderContext::VerificationResult::kForcedToSkipChecks:
- return CheckCollisionResult::kSkippedClassLoaderContextSharedLibrary;
+ *is_special_shared_library = true;
+ return true;
case ClassLoaderContext::VerificationResult::kMismatch:
- // Mismatched context, do the actual collision check.
- break;
+ *is_special_shared_library = false;
+ return false;
case ClassLoaderContext::VerificationResult::kVerifies:
- return CheckCollisionResult::kClassLoaderContextMatches;
+ *is_special_shared_library = false;
+ return true;
}
-
- // The class loader context does not match. Perform a full duplicate classes check.
- return CheckClassCollision(oat_file, context, error_msg)
- ? CheckCollisionResult::kPerformedHasCollisions : CheckCollisionResult::kNoCollisions;
+ LOG(FATAL) << "Unreachable";
}
-bool OatFileManager::AcceptOatFile(CheckCollisionResult result) const {
- // Take the file only if it has no collisions, or we must take it because of preopting.
- // Also accept oat files for shared libraries and unsupported class loaders.
- return result != CheckCollisionResult::kPerformedHasCollisions;
-}
-
-bool OatFileManager::ShouldLoadAppImage(CheckCollisionResult check_collision_result,
- const OatFile* source_oat_file,
- ClassLoaderContext* context,
- std::string* error_msg) {
+bool OatFileManager::ShouldLoadAppImage(const OatFile* source_oat_file) const {
Runtime* const runtime = Runtime::Current();
- if (kEnableAppImage && (!runtime->IsJavaDebuggable() || source_oat_file->IsDebuggable())) {
- // If we verified the class loader context (skipping due to the special marker doesn't
- // count), then also avoid the collision check.
- bool load_image = check_collision_result == CheckCollisionResult::kNoCollisions
- || check_collision_result == CheckCollisionResult::kClassLoaderContextMatches;
- // If we skipped the collision check, we need to reverify to be sure its OK to load the
- // image.
- if (!load_image &&
- check_collision_result ==
- CheckCollisionResult::kSkippedClassLoaderContextSharedLibrary) {
- // We can load the app image only if there are no collisions. If we know the
- // class loader but didn't do the full collision check in HasCollisions(),
- // do it now. b/77342775
- load_image = !CheckClassCollision(source_oat_file, context, error_msg);
- }
- return load_image;
- }
- return false;
+ return kEnableAppImage && (!runtime->IsJavaDebuggable() || source_oat_file->IsDebuggable());
}
std::vector<std::unique_ptr<const DexFile>> OatFileManager::OpenDexFilesFromOat(
@@ -461,204 +219,197 @@
CHECK(dex_location != nullptr);
CHECK(error_msgs != nullptr);
- // Verify we aren't holding the mutator lock, which could starve GC if we
- // have to generate or relocate an oat file.
+ // Verify we aren't holding the mutator lock, which could starve GC when
+ // hitting the disk.
Thread* const self = Thread::Current();
Locks::mutator_lock_->AssertNotHeld(self);
Runtime* const runtime = Runtime::Current();
- std::unique_ptr<ClassLoaderContext> context;
+ std::vector<std::unique_ptr<const DexFile>> dex_files;
+
// If the class_loader is null there's not much we can do. This happens if a dex files is loaded
// directly with DexFile APIs instead of using class loaders.
if (class_loader == nullptr) {
LOG(WARNING) << "Opening an oat file without a class loader. "
<< "Are you using the deprecated DexFile APIs?";
- context = nullptr;
} else {
- context = ClassLoaderContext::CreateContextForClassLoader(class_loader, dex_elements);
- }
+ std::unique_ptr<ClassLoaderContext> context(
+ ClassLoaderContext::CreateContextForClassLoader(class_loader, dex_elements));
- OatFileAssistant oat_file_assistant(dex_location,
- kRuntimeISA,
- runtime->GetOatFilesExecutable(),
- only_use_system_oat_files_);
+ OatFileAssistant oat_file_assistant(dex_location,
+ kRuntimeISA,
+ runtime->GetOatFilesExecutable(),
+ only_use_system_oat_files_);
- // Get the oat file on disk.
- std::unique_ptr<const OatFile> oat_file(oat_file_assistant.GetBestOatFile().release());
- VLOG(oat) << "OatFileAssistant(" << dex_location << ").GetBestOatFile()="
- << reinterpret_cast<uintptr_t>(oat_file.get())
- << " (executable=" << (oat_file != nullptr ? oat_file->IsExecutable() : false) << ")";
+ // Get the oat file on disk.
+ std::unique_ptr<const OatFile> oat_file(oat_file_assistant.GetBestOatFile().release());
+ VLOG(oat) << "OatFileAssistant(" << dex_location << ").GetBestOatFile()="
+ << reinterpret_cast<uintptr_t>(oat_file.get())
+ << " (executable=" << (oat_file != nullptr ? oat_file->IsExecutable() : false) << ")";
- const OatFile* source_oat_file = nullptr;
- CheckCollisionResult check_collision_result = CheckCollisionResult::kPerformedHasCollisions;
- std::string error_msg;
- bool accept_oat_file = false;
- if ((class_loader != nullptr || dex_elements != nullptr) && oat_file != nullptr) {
- // Prevent oat files from being loaded if no class_loader or dex_elements are provided.
- // This can happen when the deprecated DexFile.<init>(String) is called directly, and it
- // could load oat files without checking the classpath, which would be incorrect.
- // Take the file only if it has no collisions, or we must take it because of preopting.
- check_collision_result = CheckCollision(oat_file.get(), context.get(), /*out*/ &error_msg);
- accept_oat_file = AcceptOatFile(check_collision_result);
- if (!accept_oat_file) {
- // Failed the collision check. Print warning.
- if (runtime->IsDexFileFallbackEnabled()) {
- if (!oat_file_assistant.HasOriginalDexFiles()) {
- // We need to fallback but don't have original dex files. We have to
- // fallback to opening the existing oat file. This is potentially
- // unsafe so we warn about it.
- accept_oat_file = true;
+ const OatFile* source_oat_file = nullptr;
+ std::string error_msg;
+ bool is_special_shared_library = false;
+ bool class_loader_context_matches = false;
+ if (oat_file != nullptr &&
+ context != nullptr &&
+ ClassLoaderContextMatches(oat_file.get(),
+ context.get(),
+ /*out*/ &is_special_shared_library,
+ /*out*/ &error_msg)) {
+ class_loader_context_matches = true;
+ // Load the dex files from the oat file.
+ bool added_image_space = false;
+ if (oat_file->IsExecutable()) {
+ ScopedTrace app_image_timing("AppImage:Loading");
- LOG(WARNING) << "Dex location " << dex_location << " does not seem to include dex file. "
- << "Allow oat file use. This is potentially dangerous.";
- } else {
- // We have to fallback and found original dex files - extract them from an APK.
- // Also warn about this operation because it's potentially wasteful.
- LOG(WARNING) << "Found duplicate classes, falling back to extracting from APK : "
- << dex_location;
- LOG(WARNING) << "NOTE: This wastes RAM and hurts startup performance.";
+ // We need to throw away the image space if we are debuggable but the oat-file source of the
+ // image is not otherwise we might get classes with inlined methods or other such things.
+ std::unique_ptr<gc::space::ImageSpace> image_space;
+ if (!is_special_shared_library && ShouldLoadAppImage(oat_file.get())) {
+ image_space = oat_file_assistant.OpenImageSpace(oat_file.get());
}
- } else {
- // TODO: We should remove this. The fact that we're here implies -Xno-dex-file-fallback
- // was set, which means that we should never fallback. If we don't have original dex
- // files, we should just fail resolution as the flag intended.
- if (!oat_file_assistant.HasOriginalDexFiles()) {
- accept_oat_file = true;
- }
-
- LOG(WARNING) << "Found duplicate classes, dex-file-fallback disabled, will be failing to "
- " load classes for " << dex_location;
- }
-
- LOG(WARNING) << error_msg;
- }
- }
-
- std::vector<std::unique_ptr<const DexFile>> dex_files;
-
- // Load the dex files from the oat file.
- bool added_image_space = false;
- if (accept_oat_file) {
- if (oat_file->IsExecutable()) {
- ScopedTrace app_image_timing("AppImage:Loading");
-
- // We need to throw away the image space if we are debuggable but the oat-file source of the
- // image is not otherwise we might get classes with inlined methods or other such things.
- std::unique_ptr<gc::space::ImageSpace> image_space;
- if (ShouldLoadAppImage(check_collision_result,
- oat_file.get(),
- context.get(),
- &error_msg)) {
- image_space = oat_file_assistant.OpenImageSpace(oat_file.get());
- }
- if (image_space != nullptr) {
- ScopedObjectAccess soa(self);
- StackHandleScope<1> hs(self);
- Handle<mirror::ClassLoader> h_loader(
- hs.NewHandle(soa.Decode<mirror::ClassLoader>(class_loader)));
- // Can not load app image without class loader.
- if (h_loader != nullptr) {
- std::string temp_error_msg;
- // Add image space has a race condition since other threads could be reading from the
- // spaces array.
- {
- ScopedThreadSuspension sts(self, kSuspended);
- gc::ScopedGCCriticalSection gcs(self,
- gc::kGcCauseAddRemoveAppImageSpace,
- gc::kCollectorTypeAddRemoveAppImageSpace);
- ScopedSuspendAll ssa("Add image space");
- runtime->GetHeap()->AddSpace(image_space.get());
- }
- {
- ScopedTrace trace2(StringPrintf("Adding image space for location %s", dex_location));
- added_image_space = runtime->GetClassLinker()->AddImageSpace(image_space.get(),
- h_loader,
- /*out*/&dex_files,
- /*out*/&temp_error_msg);
- }
- if (added_image_space) {
- // Successfully added image space to heap, release the map so that it does not get
- // freed.
- image_space.release(); // NOLINT b/117926937
-
- // Register for tracking.
- for (const auto& dex_file : dex_files) {
- dex::tracking::RegisterDexFile(dex_file.get());
- }
- } else {
- LOG(INFO) << "Failed to add image file " << temp_error_msg;
- dex_files.clear();
+ if (image_space != nullptr) {
+ ScopedObjectAccess soa(self);
+ StackHandleScope<1> hs(self);
+ Handle<mirror::ClassLoader> h_loader(
+ hs.NewHandle(soa.Decode<mirror::ClassLoader>(class_loader)));
+ // Can not load app image without class loader.
+ if (h_loader != nullptr) {
+ std::string temp_error_msg;
+ // Add image space has a race condition since other threads could be reading from the
+ // spaces array.
{
ScopedThreadSuspension sts(self, kSuspended);
gc::ScopedGCCriticalSection gcs(self,
gc::kGcCauseAddRemoveAppImageSpace,
gc::kCollectorTypeAddRemoveAppImageSpace);
- ScopedSuspendAll ssa("Remove image space");
- runtime->GetHeap()->RemoveSpace(image_space.get());
+ ScopedSuspendAll ssa("Add image space");
+ runtime->GetHeap()->AddSpace(image_space.get());
}
- // Non-fatal, don't update error_msg.
+ {
+ ScopedTrace image_space_timing(
+ StringPrintf("Adding image space for location %s", dex_location));
+ added_image_space = runtime->GetClassLinker()->AddImageSpace(image_space.get(),
+ h_loader,
+ /*out*/&dex_files,
+ /*out*/&temp_error_msg);
+ }
+ if (added_image_space) {
+ // Successfully added image space to heap, release the map so that it does not get
+ // freed.
+ image_space.release(); // NOLINT b/117926937
+
+ // Register for tracking.
+ for (const auto& dex_file : dex_files) {
+ dex::tracking::RegisterDexFile(dex_file.get());
+ }
+ } else {
+ LOG(INFO) << "Failed to add image file " << temp_error_msg;
+ dex_files.clear();
+ {
+ ScopedThreadSuspension sts(self, kSuspended);
+ gc::ScopedGCCriticalSection gcs(self,
+ gc::kGcCauseAddRemoveAppImageSpace,
+ gc::kCollectorTypeAddRemoveAppImageSpace);
+ ScopedSuspendAll ssa("Remove image space");
+ runtime->GetHeap()->RemoveSpace(image_space.get());
+ }
+ // Non-fatal, don't update error_msg.
+ }
}
}
}
- }
- if (!added_image_space) {
- DCHECK(dex_files.empty());
+ if (!added_image_space) {
+ DCHECK(dex_files.empty());
- if (oat_file->RequiresImage()) {
- // If we could not load the image, but the OAT file requires it, we have to reload the OAT
- // file as non-executable.
- OatFileAssistant nonexecutable_oat_file_assistant(dex_location,
- kRuntimeISA,
- /*load_executable=*/false,
- only_use_system_oat_files_);
- oat_file.reset(nonexecutable_oat_file_assistant.GetBestOatFile().release());
+ if (oat_file->RequiresImage()) {
+ VLOG(oat) << "Loading "
+ << oat_file->GetLocation()
+ << "non-executable as it requires an image which we failed to load";
+ // file as non-executable.
+ OatFileAssistant nonexecutable_oat_file_assistant(dex_location,
+ kRuntimeISA,
+ /*load_executable=*/false,
+ only_use_system_oat_files_);
+ oat_file.reset(nonexecutable_oat_file_assistant.GetBestOatFile().release());
+ }
+
+ dex_files = oat_file_assistant.LoadDexFiles(*oat_file.get(), dex_location);
+
+ // Register for tracking.
+ for (const auto& dex_file : dex_files) {
+ dex::tracking::RegisterDexFile(dex_file.get());
+ }
+ }
+ if (dex_files.empty()) {
+ error_msgs->push_back("Failed to open dex files from " + oat_file->GetLocation());
+ } else {
+ // Opened dex files from an oat file, madvise them to their loaded state.
+ for (const std::unique_ptr<const DexFile>& dex_file : dex_files) {
+ OatDexFile::MadviseDexFile(*dex_file, MadviseState::kMadviseStateAtLoad);
+ }
}
- dex_files = oat_file_assistant.LoadDexFiles(*oat_file.get(), dex_location);
+ VLOG(class_linker) << "Registering " << oat_file->GetLocation();
+ source_oat_file = RegisterOatFile(std::move(oat_file));
+ *out_oat_file = source_oat_file;
+ } else if (!error_msg.empty()) {
+ LOG(WARNING) << error_msg;
+ }
- // Register for tracking.
- for (const auto& dex_file : dex_files) {
- dex::tracking::RegisterDexFile(dex_file.get());
+ // Verify if any of the dex files being loaded is already in the class path.
+ // If so, report an error with the current stack trace.
+ // Most likely the developer didn't intend to do this because it will waste
+ // performance and memory.
+ if (context != nullptr && !class_loader_context_matches) {
+ std::set<const DexFile*> already_exists_in_classpath =
+ context->CheckForDuplicateDexFiles(MakeNonOwningPointerVector(dex_files));
+ if (!already_exists_in_classpath.empty()) {
+ auto duplicate_it = already_exists_in_classpath.begin();
+ std::string duplicates = (*duplicate_it)->GetLocation();
+ for (duplicate_it++ ; duplicate_it != already_exists_in_classpath.end(); duplicate_it++) {
+ duplicates += "," + (*duplicate_it)->GetLocation();
+ }
+
+ std::ostringstream out;
+ out << "Trying to load dex files which is already loaded in the same ClassLoader "
+ << "hierarchy.\n"
+ << "This is a strong indication of bad ClassLoader construct which leads to poor "
+ << "performance and wastes memory.\n"
+ << "The list of duplicate dex files is: " << duplicates << "\n"
+ << "The current class loader context is: "
+ << context->EncodeContextForOatFile("") << "\n"
+ << "Java stack trace:\n";
+
+ {
+ ScopedObjectAccess soa(self);
+ self->DumpJavaStack(out);
+ }
+
+ // We log this as an ERROR to stress the fact that this is most likely unintended.
+ // Note that ART cannot do anything about it. It is up to the app to fix their logic.
+ // Here we are trying to give a heads up on why the app might have performance issues.
+ LOG(ERROR) << out.str();
}
}
- if (dex_files.empty()) {
- error_msgs->push_back("Failed to open dex files from " + oat_file->GetLocation());
- } else {
- // Opened dex files from an oat file, madvise them to their loaded state.
- for (const std::unique_ptr<const DexFile>& dex_file : dex_files) {
- OatDexFile::MadviseDexFile(*dex_file, MadviseState::kMadviseStateAtLoad);
- }
- }
-
- VLOG(class_linker) << "Registering " << oat_file->GetLocation();
- source_oat_file = RegisterOatFile(std::move(oat_file));
- *out_oat_file = source_oat_file;
}
- // Fall back to running out of the original dex file if we couldn't load any
- // dex_files from the oat file.
+ // If we arrive here with an empty dex files list, it means we fail to load
+ // it/them through an .oat file.
if (dex_files.empty()) {
- if (oat_file_assistant.HasOriginalDexFiles()) {
- if (Runtime::Current()->IsDexFileFallbackEnabled()) {
- static constexpr bool kVerifyChecksum = true;
- const ArtDexFileLoader dex_file_loader;
- if (!dex_file_loader.Open(dex_location,
- dex_location,
- Runtime::Current()->IsVerificationEnabled(),
- kVerifyChecksum,
- /*out*/ &error_msg,
- &dex_files)) {
- LOG(WARNING) << error_msg;
- error_msgs->push_back("Failed to open dex files from " + std::string(dex_location)
- + " because: " + error_msg);
- }
- } else {
- error_msgs->push_back("Fallback mode disabled, skipping dex files.");
- }
- } else {
- std::string msg = StringPrintf("No original dex files found for dex location (%s) %s",
- GetInstructionSetString(kRuntimeISA), dex_location);
- error_msgs->push_back(msg);
+ std::string error_msg;
+ static constexpr bool kVerifyChecksum = true;
+ const ArtDexFileLoader dex_file_loader;
+ if (!dex_file_loader.Open(dex_location,
+ dex_location,
+ Runtime::Current()->IsVerificationEnabled(),
+ kVerifyChecksum,
+ /*out*/ &error_msg,
+ &dex_files)) {
+ LOG(WARNING) << error_msg;
+ error_msgs->push_back("Failed to open dex files from " + std::string(dex_location)
+ + " because: " + error_msg);
}
}
@@ -666,42 +417,6 @@
Runtime::Current()->GetJit()->RegisterDexFiles(dex_files, class_loader);
}
- // Verify if any of the dex files being loaded is already in the class path.
- // If so, report an error with the current stack trace.
- // Most likely the developer didn't intend to do this because it will waste
- // performance and memory.
- // We perform the check only if the class loader context match failed or did
- // not run (e.g. not that we do not run the check if we don't have an oat file).
- if (context != nullptr
- && check_collision_result != CheckCollisionResult::kClassLoaderContextMatches) {
- std::set<const DexFile*> already_exists_in_classpath =
- context->CheckForDuplicateDexFiles(MakeNonOwningPointerVector(dex_files));
- if (!already_exists_in_classpath.empty()) {
- auto duplicate_it = already_exists_in_classpath.begin();
- std::string duplicates = (*duplicate_it)->GetLocation();
- for (duplicate_it++ ; duplicate_it != already_exists_in_classpath.end(); duplicate_it++) {
- duplicates += "," + (*duplicate_it)->GetLocation();
- }
-
- std::ostringstream out;
- out << "Trying to load dex files which is already loaded in the same ClassLoader hierarchy.\n"
- << "This is a strong indication of bad ClassLoader construct which leads to poor "
- << "performance and wastes memory.\n"
- << "The list of duplicate dex files is: " << duplicates << "\n"
- << "The current class loader context is: " << context->EncodeContextForOatFile("") << "\n"
- << "Java stack trace:\n";
-
- {
- ScopedObjectAccess soa(self);
- self->DumpJavaStack(out);
- }
-
- // We log this as an ERROR to stress the fact that this is most likely unintended.
- // Note that ART cannot do anything about it. It is up to the app to fix their logic.
- // Here we are trying to give a heads up on why the app might have performance issues.
- LOG(ERROR) << out.str();
- }
- }
return dex_files;
}
diff --git a/runtime/oat_file_manager.h b/runtime/oat_file_manager.h
index 9c3a38a..11eabe2 100644
--- a/runtime/oat_file_manager.h
+++ b/runtime/oat_file_manager.h
@@ -141,15 +141,6 @@
static constexpr size_t kAnonymousVdexCacheSize = 8u;
private:
- enum class CheckCollisionResult {
- kSkippedUnsupportedClassLoader,
- kSkippedClassLoaderContextSharedLibrary,
- kSkippedVerificationDisabled,
- kNoCollisions,
- kPerformedHasCollisions,
- kClassLoaderContextMatches
- };
-
std::vector<std::unique_ptr<const DexFile>> OpenDexFilesFromOat_Impl(
std::vector<MemMap>&& dex_mem_maps,
jobject class_loader,
@@ -158,31 +149,11 @@
/*out*/ std::vector<std::string>* error_msgs)
REQUIRES(!Locks::oat_file_manager_lock_, !Locks::mutator_lock_);
- // Check that the class loader context of the given oat file matches the given context.
- // This will perform a check that all class loaders in the chain have the same type and
- // classpath.
- // If the context is null (which means the initial class loader was null or unsupported)
- // this returns kSkippedUnsupportedClassLoader.
- // If the context does not validate the method will check for duplicate class definitions of
- // the given oat file against the oat files (either from the class loaders if possible or all
- // non-boot oat files otherwise).
- // Return kPerformedHasCollisions if there are any class definition collisions in the oat_file.
- CheckCollisionResult CheckCollision(const OatFile* oat_file,
- const ClassLoaderContext* context,
- /*out*/ std::string* error_msg) const
- REQUIRES(!Locks::oat_file_manager_lock_);
-
const OatFile* FindOpenedOatFileFromOatLocationLocked(const std::string& oat_location) const
REQUIRES(Locks::oat_file_manager_lock_);
- // Return true if we should accept the oat file.
- bool AcceptOatFile(CheckCollisionResult result) const;
-
// Return true if we should attempt to load the app image.
- bool ShouldLoadAppImage(CheckCollisionResult check_collision_result,
- const OatFile* source_oat_file,
- ClassLoaderContext* context,
- std::string* error_msg);
+ bool ShouldLoadAppImage(const OatFile* source_oat_file) const;
std::set<std::unique_ptr<const OatFile>> oat_files_ GUARDED_BY(Locks::oat_file_manager_lock_);
diff --git a/runtime/parsed_options.cc b/runtime/parsed_options.cc
index c62caa9..5bb9ed6 100644
--- a/runtime/parsed_options.cc
+++ b/runtime/parsed_options.cc
@@ -321,8 +321,6 @@
.Define("-Xzygote-max-boot-retry=_")
.WithType<unsigned int>()
.IntoKey(M::ZygoteMaxFailedBoots)
- .Define("-Xno-dex-file-fallback")
- .IntoKey(M::NoDexFileFallback)
.Define("-Xno-sig-chain")
.IntoKey(M::NoSigChain)
.Define("--cpu-abilist=_")
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index 1c1159a..fc1a3c8 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -268,7 +268,6 @@
dump_gc_performance_on_shutdown_(false),
preinitialization_transactions_(),
verify_(verifier::VerifyMode::kNone),
- allow_dex_file_fallback_(true),
target_sdk_version_(static_cast<uint32_t>(SdkVersion::kUnset)),
implicit_null_checks_(false),
implicit_so_checks_(false),
@@ -1315,7 +1314,6 @@
intern_table_ = new InternTable;
verify_ = runtime_options.GetOrDefault(Opt::Verify);
- allow_dex_file_fallback_ = !runtime_options.Exists(Opt::NoDexFileFallback);
target_sdk_version_ = runtime_options.GetOrDefault(Opt::TargetSdkVersion);
@@ -1419,11 +1417,6 @@
runtime_options.Exists(Opt::DumpRegionInfoAfterGC),
image_space_loading_order_);
- if (!heap_->HasBootImageSpace() && !allow_dex_file_fallback_) {
- LOG(ERROR) << "Dex file fallback disabled, cannot continue without image.";
- return false;
- }
-
dump_gc_performance_on_shutdown_ = runtime_options.Exists(Opt::DumpGCPerformanceOnShutdown);
jdwp_options_ = runtime_options.GetOrDefault(Opt::JdwpOptions);
diff --git a/runtime/runtime.h b/runtime/runtime.h
index 822c0ac..594edaa 100644
--- a/runtime/runtime.h
+++ b/runtime/runtime.h
@@ -656,10 +656,6 @@
}
}
- bool IsDexFileFallbackEnabled() const {
- return allow_dex_file_fallback_;
- }
-
const std::vector<std::string>& GetCpuAbilist() const {
return cpu_abilist_;
}
@@ -1172,10 +1168,6 @@
// If kNone, verification is disabled. kEnable by default.
verifier::VerifyMode verify_;
- // If true, the runtime may use dex files directly with the interpreter if an oat file is not
- // available/usable.
- bool allow_dex_file_fallback_;
-
// List of supported cpu abis.
std::vector<std::string> cpu_abilist_;
diff --git a/runtime/runtime_options.def b/runtime/runtime_options.def
index 5707a33..a342973 100644
--- a/runtime/runtime_options.def
+++ b/runtime/runtime_options.def
@@ -133,7 +133,6 @@
hiddenapi::EnforcementPolicy::kDisabled)
RUNTIME_OPTIONS_KEY (std::string, NativeBridge)
RUNTIME_OPTIONS_KEY (unsigned int, ZygoteMaxFailedBoots, 10)
-RUNTIME_OPTIONS_KEY (Unit, NoDexFileFallback)
RUNTIME_OPTIONS_KEY (std::string, CpuAbiList)
RUNTIME_OPTIONS_KEY (std::string, Fingerprint)
RUNTIME_OPTIONS_KEY (ExperimentalFlags, Experimental, ExperimentalFlags::kNone) // -Xexperimental:{...}