Revert "Integrate ClassLoaderContext check in OatFileAssistant::GetBestOatFile."
This reverts commit c8fe6517faf91b45683cddff3c15e08e489e12e9.
Reason for revert: Breaks 1002-notify-startup (flaky)
Test: "art/test.py -r --host -t 1002" in a loop
Bug: 176960283
Change-Id: I4f5467efa5a1e09452b28b86b183791e4105b19e
diff --git a/dexoptanalyzer/dexoptanalyzer.cc b/dexoptanalyzer/dexoptanalyzer.cc
index 998f41a..5f501d6 100644
--- a/dexoptanalyzer/dexoptanalyzer.cc
+++ b/dexoptanalyzer/dexoptanalyzer.cc
@@ -298,23 +298,10 @@
Usage("Invalid --class-loader-context '%s'", context_str_.c_str());
}
}
- if (class_loader_context != nullptr) {
- size_t dir_index = dex_file_.rfind('/');
- std::string classpath_dir = (dir_index != std::string::npos)
- ? dex_file_.substr(0, dir_index)
- : "";
-
- if (!class_loader_context->OpenDexFiles(classpath_dir,
- context_fds_,
- /*only_read_checksums=*/ true)) {
- return ReturnCode::kDex2OatFromScratch;
- }
- }
std::unique_ptr<OatFileAssistant> oat_file_assistant;
oat_file_assistant = std::make_unique<OatFileAssistant>(dex_file_.c_str(),
isa_,
- class_loader_context.get(),
/*load_executable=*/ false,
/*only_load_system_executable=*/ false,
vdex_fd_,
@@ -327,6 +314,8 @@
}
int dexoptNeeded = oat_file_assistant->GetDexOptNeeded(compiler_filter_,
+ class_loader_context.get(),
+ context_fds_,
assume_profile_changed_,
downgrade_);
diff --git a/dexoptanalyzer/dexoptanalyzer_test.cc b/dexoptanalyzer/dexoptanalyzer_test.cc
index ef6282a..42be473 100644
--- a/dexoptanalyzer/dexoptanalyzer_test.cc
+++ b/dexoptanalyzer/dexoptanalyzer_test.cc
@@ -79,23 +79,18 @@
bool assume_profile_changed = false,
bool downgrade = false,
const char* class_loader_context = "PCL[]") {
- std::unique_ptr<ClassLoaderContext> context = class_loader_context == nullptr
- ? nullptr
- : ClassLoaderContext::Create(class_loader_context);
- if (context != nullptr) {
- std::vector<int> context_fds;
- ASSERT_TRUE(context->OpenDexFiles("", context_fds, /*only_read_checksums*/ true));
- }
-
int dexoptanalyzerResult = Analyze(
dex_file, compiler_filter, assume_profile_changed, class_loader_context);
dexoptanalyzerResult = DexoptanalyzerToOatFileAssistant(dexoptanalyzerResult);
- OatFileAssistant oat_file_assistant(dex_file.c_str(),
- kRuntimeISA,
- context.get(),
- /*load_executable=*/ false);
+ OatFileAssistant oat_file_assistant(dex_file.c_str(), kRuntimeISA, /*load_executable=*/ false);
+ std::vector<int> context_fds;
+
+ std::unique_ptr<ClassLoaderContext> context = class_loader_context == nullptr
+ ? nullptr
+ : ClassLoaderContext::Create(class_loader_context);
+
int assistantResult = oat_file_assistant.GetDexOptNeeded(
- compiler_filter, assume_profile_changed, downgrade);
+ compiler_filter, context.get(), context_fds, assume_profile_changed, downgrade);
EXPECT_EQ(assistantResult, dexoptanalyzerResult);
}
};
diff --git a/runtime/class_loader_context.cc b/runtime/class_loader_context.cc
index 228b950..b5ce122 100644
--- a/runtime/class_loader_context.cc
+++ b/runtime/class_loader_context.cc
@@ -412,9 +412,7 @@
// no dex files. So that we can distinguish the real failures...
const ArtDexFileLoader dex_file_loader;
std::vector<ClassLoaderInfo*> work_list;
- if (class_loader_chain_ == nullptr) {
- return true;
- }
+ CHECK(class_loader_chain_ != nullptr);
work_list.push_back(class_loader_chain_.get());
size_t dex_file_index = 0;
while (!work_list.empty()) {
@@ -1157,9 +1155,7 @@
jobjectArray dex_elements) {
ScopedTrace trace(__FUNCTION__);
- if (class_loader == nullptr) {
- return nullptr;
- }
+ CHECK(class_loader != nullptr);
ScopedObjectAccess soa(Thread::Current());
StackHandleScope<2> hs(soa.Self());
Handle<mirror::ClassLoader> h_class_loader =
diff --git a/runtime/native/dalvik_system_DexFile.cc b/runtime/native/dalvik_system_DexFile.cc
index f8ad7f1..1c4adab 100644
--- a/runtime/native/dalvik_system_DexFile.cc
+++ b/runtime/native/dalvik_system_DexFile.cc
@@ -18,7 +18,6 @@
#include <sstream>
-#include "android-base/file.h"
#include "android-base/stringprintf.h"
#include "base/casts.h"
@@ -542,26 +541,22 @@
env->ThrowNew(iae.get(), message.c_str());
return -1;
}
- std::vector<int> context_fds;
- context->OpenDexFiles(android::base::Dirname(filename),
- context_fds,
- /*only_read_checksums*/ true);
}
// TODO: Verify the dex location is well formed, and throw an IOException if
// not?
- OatFileAssistant oat_file_assistant(filename,
- target_instruction_set,
- context.get(),
- /* load_executable= */ false);
+ OatFileAssistant oat_file_assistant(filename, target_instruction_set, false);
// Always treat elements of the bootclasspath as up-to-date.
if (oat_file_assistant.IsInBootClassPath()) {
return OatFileAssistant::kNoDexOptNeeded;
}
+ std::vector<int> context_fds;
return oat_file_assistant.GetDexOptNeeded(filter,
+ context.get(),
+ context_fds,
profile_changed,
downgrade);
}
@@ -589,9 +584,7 @@
return nullptr;
}
- OatFileAssistant oat_file_assistant(filename.c_str(),
- target_instruction_set,
- /* context= */ nullptr,
+ OatFileAssistant oat_file_assistant(filename.c_str(), target_instruction_set,
/* load_executable= */ false);
return env->NewStringUTF(oat_file_assistant.GetStatusDump().c_str());
}
@@ -698,10 +691,7 @@
return JNI_FALSE;
}
- OatFileAssistant oat_file_assistant(filename,
- kRuntimeISA,
- /* context= */ nullptr,
- /* load_executable= */ false);
+ OatFileAssistant oat_file_assistant(filename, kRuntimeISA, false);
return oat_file_assistant.IsUpToDate() ? JNI_FALSE : JNI_TRUE;
}
@@ -838,11 +828,10 @@
}
}
- // If we did not find a boot classpath oat file, lookup the oat file for an app.
+ // If did not find a boot classpath oat file, lookup the oat file for an app.
if (oat_filename.empty()) {
OatFileAssistant oat_file_assistant(filename.c_str(),
target_instruction_set,
- /* context= */ nullptr,
/* load_executable= */ false);
std::unique_ptr<OatFile> best_oat_file = oat_file_assistant.GetBestOatFile();
diff --git a/runtime/oat_file_assistant.cc b/runtime/oat_file_assistant.cc
index 0bccc82..245ae36 100644
--- a/runtime/oat_file_assistant.cc
+++ b/runtime/oat_file_assistant.cc
@@ -21,7 +21,6 @@
#include <sys/stat.h>
#include "zlib.h"
-#include "android-base/file.h"
#include "android-base/stringprintf.h"
#include "android-base/strings.h"
@@ -68,9 +67,8 @@
case OatFileAssistant::kOatUpToDate:
stream << "kOatUpToDate";
break;
- case OatFileAssistant::kOatContextOutOfDate:
- stream << "kOaContextOutOfDate";
- break;
+ default:
+ UNREACHABLE();
}
return stream;
@@ -78,12 +76,10 @@
OatFileAssistant::OatFileAssistant(const char* dex_location,
const InstructionSet isa,
- ClassLoaderContext* context,
bool load_executable,
bool only_load_system_executable)
: OatFileAssistant(dex_location,
isa,
- context,
load_executable,
only_load_system_executable,
/*vdex_fd=*/ -1,
@@ -93,14 +89,12 @@
OatFileAssistant::OatFileAssistant(const char* dex_location,
const InstructionSet isa,
- ClassLoaderContext* context,
bool load_executable,
bool only_load_system_executable,
int vdex_fd,
int oat_fd,
int zip_fd)
- : context_(context),
- isa_(isa),
+ : isa_(isa),
load_executable_(load_executable),
only_load_system_executable_(only_load_system_executable),
odex_(this, /*is_oat_location=*/ false),
@@ -109,7 +103,6 @@
vdex_for_oat_(this, /*is_oat_location=*/ true),
zip_fd_(zip_fd) {
CHECK(dex_location != nullptr) << "OatFileAssistant: null dex location";
- CHECK(!load_executable || context != nullptr) << "Loading executable without a context";
if (zip_fd < 0) {
CHECK_LE(oat_fd, 0) << "zip_fd must be provided with valid oat_fd. zip_fd=" << zip_fd
@@ -199,10 +192,14 @@
}
int OatFileAssistant::GetDexOptNeeded(CompilerFilter::Filter target,
+ ClassLoaderContext* class_loader_context,
+ const std::vector<int>& context_fds,
bool profile_changed,
bool downgrade) {
OatFileInfo& info = GetBestInfo();
DexOptNeeded dexopt_needed = info.GetDexOptNeeded(target,
+ class_loader_context,
+ context_fds,
profile_changed,
downgrade);
if (info.IsOatLocation() || dexopt_needed == kDex2OatFromScratch) {
@@ -446,10 +443,6 @@
return kOatDexOutOfDate;
}
- if (!ClassLoaderContextIsOkay(file)) {
- return kOatContextOutOfDate;
- }
-
return kOatUpToDate;
}
@@ -734,7 +727,6 @@
switch (Status()) {
case kOatCannotOpen:
case kOatDexOutOfDate:
- case kOatContextOutOfDate:
case kOatBootImageOutOfDate: return false;
case kOatUpToDate: return true;
@@ -760,17 +752,29 @@
OatFileAssistant::DexOptNeeded OatFileAssistant::OatFileInfo::GetDexOptNeeded(
CompilerFilter::Filter target,
+ ClassLoaderContext* context,
+ const std::vector<int>& context_fds,
bool profile_changed,
bool downgrade) {
- if (IsUseable()) {
- return CompilerFilterIsOkay(target, profile_changed, downgrade)
- ? kNoDexOptNeeded
- : kDex2OatForFilter;
- }
+ bool filter_okay = CompilerFilterIsOkay(target, profile_changed, downgrade);
+ bool class_loader_context_okay = ClassLoaderContextIsOkay(context, context_fds);
- if (Status() == kOatBootImageOutOfDate) {
- return kDex2OatForBootImage;
+ // Only check the filter and relocation if the class loader context is ok.
+ // If it is not, we will return kDex2OatFromScratch as the compilation needs to be redone.
+ if (class_loader_context_okay) {
+ if (filter_okay && Status() == kOatUpToDate) {
+ // The oat file is in good shape as is.
+ return kNoDexOptNeeded;
+ }
+
+ if (IsUseable()) {
+ return kDex2OatForFilter;
+ }
+
+ if (Status() == kOatBootImageOutOfDate) {
+ return kDex2OatForBootImage;
+ }
}
if (oat_file_assistant_->HasDexFiles()) {
@@ -883,36 +887,51 @@
CompilerFilter::IsAsGoodAs(current, target);
}
-bool OatFileAssistant::ClassLoaderContextIsOkay(const OatFile& oat_file) const {
- if (oat_file.IsBackedByVdexOnly()) {
+bool OatFileAssistant::OatFileInfo::ClassLoaderContextIsOkay(ClassLoaderContext* context,
+ const std::vector<int>& context_fds) {
+ const OatFile* file = GetFile();
+ if (file == nullptr) {
+ // No oat file means we have nothing to verify.
+ return true;
+ }
+
+ if (file->IsBackedByVdexOnly()) {
// Only a vdex file, we don't depend on the class loader context.
return true;
}
- if (!CompilerFilter::IsVerificationEnabled(oat_file.GetCompilerFilter())) {
+ if (!CompilerFilter::IsVerificationEnabled(file->GetCompilerFilter())) {
// If verification is not enabled we don't need to verify the class loader context and we
// assume it's ok.
return true;
}
- if (context_ == nullptr) {
- // When no class loader context is provided (which happens for deprecated
- // DexFile APIs), just assume it is OK.
- return true;
- }
- ClassLoaderContext::VerificationResult matches = context_->VerifyClassLoaderContextMatch(
- oat_file.GetClassLoaderContext(),
- /*verify_names=*/ true,
- /*verify_checksums=*/ true);
- if (matches == ClassLoaderContext::VerificationResult::kMismatch) {
- VLOG(oat) << "ClassLoaderContext check failed. Context was "
- << oat_file.GetClassLoaderContext()
- << ". The expected context is "
- << context_->EncodeContextForOatFile(android::base::Dirname(dex_location_));
+ if (context == nullptr) {
+ // TODO(calin): stop using null for the unkown contexts.
+ // b/148494302 introduces runtime encoding for unknown context which will make this possible.
+ VLOG(oat) << "ClassLoaderContext check failed: uknown(null) context";
return false;
}
- return true;
+
+ size_t dir_index = oat_file_assistant_->dex_location_.rfind('/');
+ std::string classpath_dir = (dir_index != std::string::npos)
+ ? oat_file_assistant_->dex_location_.substr(0, dir_index)
+ : "";
+
+ if (!context->OpenDexFiles(classpath_dir, context_fds, /*only_read_checksums*/ true)) {
+ VLOG(oat) << "ClassLoaderContext check failed: dex files from the context could not be opened";
+ return false;
+ }
+
+ const bool result = context->VerifyClassLoaderContextMatch(file->GetClassLoaderContext()) !=
+ ClassLoaderContext::VerificationResult::kMismatch;
+ if (!result) {
+ VLOG(oat) << "ClassLoaderContext check failed. Context was "
+ << file->GetClassLoaderContext()
+ << ". The expected context is " << context->EncodeContextForOatFile(classpath_dir);
+ }
+ return result;
}
bool OatFileAssistant::OatFileInfo::IsExecutable() {
@@ -964,10 +983,7 @@
std::string* out_compilation_reason) {
// It may not be possible to load an oat file executable (e.g., selinux restrictions). Load
// non-executable and check the status manually.
- OatFileAssistant oat_file_assistant(filename.c_str(),
- isa,
- /* context= */ nullptr,
- /*load_executable=*/ false);
+ OatFileAssistant oat_file_assistant(filename.c_str(), isa, /*load_executable=*/ false);
std::string out_odex_location; // unused
std::string out_odex_status; // unused
oat_file_assistant.GetOptimizationStatus(
@@ -1022,11 +1038,6 @@
*out_odex_status = "boot-image-more-recent";
return;
- case kOatContextOutOfDate:
- *out_compilation_filter = "run-from-apk-fallback";
- *out_odex_status = "context-mismatch";
- return;
-
case kOatDexOutOfDate:
*out_compilation_filter = "run-from-apk-fallback";
*out_odex_status = "apk-more-recent";
diff --git a/runtime/oat_file_assistant.h b/runtime/oat_file_assistant.h
index 50b54af..e771dcc 100644
--- a/runtime/oat_file_assistant.h
+++ b/runtime/oat_file_assistant.h
@@ -80,10 +80,6 @@
// dex file, but is out of date with respect to the boot image.
kOatBootImageOutOfDate,
- // kOatContextOutOfDate - The context in the oat file is out of date with
- // respect to the class loader context.
- kOatContextOutOfDate,
-
// kOatUpToDate - The oat file is completely up to date with respect to
// the dex file and boot image.
kOatUpToDate,
@@ -111,7 +107,6 @@
// only oat files from /system loaded executable.
OatFileAssistant(const char* dex_location,
const InstructionSet isa,
- ClassLoaderContext* context,
bool load_executable,
bool only_load_system_executable = false);
@@ -120,7 +115,6 @@
// Otherwise, dex_location will be used to construct necessary filenames.
OatFileAssistant(const char* dex_location,
const InstructionSet isa,
- ClassLoaderContext* context,
bool load_executable,
bool only_load_system_executable,
int vdex_fd,
@@ -148,6 +142,8 @@
// the oat location. Returns a negative status code if the status refers to
// the oat file in the odex location.
int GetDexOptNeeded(CompilerFilter::Filter target_compiler_filter,
+ ClassLoaderContext* context,
+ const std::vector<int>& context_fds,
bool profile_changed = false,
bool downgrade = false);
@@ -231,10 +227,6 @@
// Returns the status of the oat file for the dex location.
OatStatus OatFileStatus();
- OatStatus GetBestStatus() {
- return GetBestInfo().Status();
- }
-
// Constructs the odex file name for the given dex location.
// Returns true on success, in which case odex_filename is set to the odex
// file name.
@@ -270,8 +262,6 @@
// anonymous dex file(s) created by AnonymousDexVdexLocation.
static bool IsAnonymousVdexBasename(const std::string& basename);
- bool ClassLoaderContextIsOkay(const OatFile& oat_file) const;
-
private:
class OatFileInfo {
public:
@@ -304,6 +294,8 @@
// downgrade should be true if the purpose of dexopt is to downgrade the
// compiler filter.
DexOptNeeded GetDexOptNeeded(CompilerFilter::Filter target_compiler_filter,
+ ClassLoaderContext* context,
+ const std::vector<int>& context_fds,
bool profile_changed,
bool downgrade);
@@ -346,6 +338,8 @@
// compiler filter.
bool CompilerFilterIsOkay(CompilerFilter::Filter target, bool profile_changed, bool downgrade);
+ bool ClassLoaderContextIsOkay(ClassLoaderContext* context, const std::vector<int>& context_fds);
+
// Release the loaded oat file.
// Returns null if the oat file hasn't been loaded.
//
@@ -413,8 +407,6 @@
std::string dex_location_;
- ClassLoaderContext* context_;
-
// Whether or not the parent directory of the dex file is writable.
bool dex_parent_writable_ = false;
diff --git a/runtime/oat_file_assistant_test.cc b/runtime/oat_file_assistant_test.cc
index 5631e12..16d3ce0 100644
--- a/runtime/oat_file_assistant_test.cc
+++ b/runtime/oat_file_assistant_test.cc
@@ -98,24 +98,32 @@
}
}
+ int GetDexOptNeeded(OatFileAssistant* assistant,
+ CompilerFilter::Filter compiler_filter,
+ bool profile_changed) {
+ std::vector<int> context_fds;
+ return GetDexOptNeeded(assistant,
+ compiler_filter,
+ ClassLoaderContext::Default(),
+ context_fds,
+ profile_changed,
+ /*downgrade=*/ false);
+ }
+
int GetDexOptNeeded(
OatFileAssistant* assistant,
CompilerFilter::Filter compiler_filter,
+ const std::unique_ptr<ClassLoaderContext>& context = ClassLoaderContext::Default(),
+ const std::vector<int>& context_fds = std::vector<int>(),
bool profile_changed = false,
bool downgrade = false) {
return assistant->GetDexOptNeeded(
compiler_filter,
+ context.get(),
+ context_fds,
profile_changed,
downgrade);
}
-
- static std::unique_ptr<ClassLoaderContext> InitializeDefaultContext() {
- auto context = ClassLoaderContext::Default();
- context->OpenDexFiles();
- return context;
- }
-
- std::unique_ptr<ClassLoaderContext> default_context_ = InitializeDefaultContext();
};
class ScopedNonWritable {
@@ -173,10 +181,7 @@
ASSERT_TRUE(Dex2Oat(args, &error_msg)) << error_msg;
// Verify we can load both dex files.
- OatFileAssistant oat_file_assistant(dex_location.c_str(),
- kRuntimeISA,
- default_context_.get(),
- true);
+ OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
ASSERT_TRUE(oat_file.get() != nullptr);
@@ -193,13 +198,13 @@
Copy(GetDexSrc1(), dex_location);
Copy(GetDexSrc2(), context_location);
+ OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
+
std::string context_str = "PCL[" + context_location + "]";
std::unique_ptr<ClassLoaderContext> context = ClassLoaderContext::Create(context_str);
ASSERT_TRUE(context != nullptr);
ASSERT_TRUE(context->OpenDexFiles());
- OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, context.get(), false);
-
std::string error_msg;
std::vector<std::string> args;
args.push_back("--dex-file=" + dex_location);
@@ -208,8 +213,7 @@
ASSERT_TRUE(Dex2Oat(args, &error_msg)) << error_msg;
std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
- ASSERT_NE(nullptr, oat_file.get());
- ASSERT_NE(nullptr, oat_file->GetOatHeader().GetStoreValueByKey(OatHeader::kClassPathKey));
+ EXPECT_NE(nullptr, oat_file.get());
EXPECT_EQ(context->EncodeContextForOatFile(""),
oat_file->GetOatHeader().GetStoreValueByKey(OatHeader::kClassPathKey));
}
@@ -221,27 +225,27 @@
Copy(GetDexSrc1(), dex_location);
Copy(GetDexSrc2(), context_location);
- // A relative context simulates a dependent split context.
- std::unique_ptr<ClassLoaderContext> relative_context =
- ClassLoaderContext::Create("PCL[ContextDex.jar]");
- ASSERT_TRUE(relative_context != nullptr);
- std::vector<int> context_fds;
- ASSERT_TRUE(relative_context->OpenDexFiles(GetScratchDir(), context_fds));
+ OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
- OatFileAssistant oat_file_assistant(dex_location.c_str(),
- kRuntimeISA,
- relative_context.get(),
- false);
+ std::string context_str = "PCL[" + context_location + "]";
+ std::unique_ptr<ClassLoaderContext> context = ClassLoaderContext::Create(context_str);
+ ASSERT_TRUE(context != nullptr);
+ ASSERT_TRUE(context->OpenDexFiles());
std::string error_msg;
std::vector<std::string> args;
args.push_back("--dex-file=" + dex_location);
args.push_back("--oat-file=" + odex_location);
- args.push_back("--class-loader-context=PCL[" + context_location + "]");
+ args.push_back("--class-loader-context=" + context_str);
ASSERT_TRUE(Dex2Oat(args, &error_msg)) << error_msg;
+ // A relative context simulates a dependent split context.
+ std::unique_ptr<ClassLoaderContext> relative_context =
+ ClassLoaderContext::Create("PCL[ContextDex.jar]");
EXPECT_EQ(-OatFileAssistant::kNoDexOptNeeded,
- GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kDefaultCompilerFilter));
+ GetDexOptNeeded(&oat_file_assistant,
+ CompilerFilter::kDefaultCompilerFilter,
+ relative_context));
}
// Case: We have a DEX file, but no OAT file for it.
@@ -250,10 +254,7 @@
std::string dex_location = GetScratchDir() + "/DexNoOat.jar";
Copy(GetDexSrc1(), dex_location);
- OatFileAssistant oat_file_assistant(dex_location.c_str(),
- kRuntimeISA,
- default_context_.get(),
- false);
+ OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
EXPECT_EQ(OatFileAssistant::kDex2OatFromScratch,
GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kExtract));
@@ -282,10 +283,7 @@
TEST_F(OatFileAssistantTest, NoDexNoOat) {
std::string dex_location = GetScratchDir() + "/NoDexNoOat.jar";
- OatFileAssistant oat_file_assistant(dex_location.c_str(),
- kRuntimeISA,
- default_context_.get(),
- true);
+ OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kSpeed));
@@ -306,10 +304,7 @@
// Force the use of oat location by making the dex parent not writable.
OatFileAssistant oat_file_assistant(
- dex_location.c_str(),
- kRuntimeISA,
- default_context_.get(),
- /*load_executable=*/ false);
+ dex_location.c_str(), kRuntimeISA, /*load_executable=*/ false);
EXPECT_EQ(-OatFileAssistant::kNoDexOptNeeded,
GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kSpeed));
@@ -346,10 +341,7 @@
// Force the use of oat location by making the dex parent not writable.
OatFileAssistant oat_file_assistant(
- dex_location.c_str(),
- kRuntimeISA,
- default_context_.get(),
- /*load_executable=*/ false);
+ dex_location.c_str(), kRuntimeISA, /*load_executable=*/ false);
EXPECT_EQ(-OatFileAssistant::kNoDexOptNeeded,
GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kSpeed));
@@ -389,10 +381,7 @@
ASSERT_EQ(0, symlink(scratch_dir.c_str(), link.c_str()));
dex_location = link + "/OdexUpToDate.jar";
- OatFileAssistant oat_file_assistant(dex_location.c_str(),
- kRuntimeISA,
- default_context_.get(),
- false);
+ OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
EXPECT_EQ(-OatFileAssistant::kNoDexOptNeeded,
GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kSpeed));
@@ -426,10 +415,7 @@
ScopedNonWritable scoped_non_writable(dex_location);
ASSERT_TRUE(scoped_non_writable.IsSuccessful());
- OatFileAssistant oat_file_assistant(dex_location.c_str(),
- kRuntimeISA,
- default_context_.get(),
- false);
+ OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kSpeed));
@@ -472,7 +458,6 @@
OatFileAssistant oat_file_assistant(dex_location.c_str(),
kRuntimeISA,
- default_context_.get(),
false,
false,
vdex_fd.get(),
@@ -511,7 +496,6 @@
OatFileAssistant oat_file_assistant(dex_location.c_str(),
kRuntimeISA,
- default_context_.get(),
false,
false,
vdex_fd.get(),
@@ -547,7 +531,6 @@
OatFileAssistant oat_file_assistant(dex_location.c_str(),
kRuntimeISA,
- default_context_.get(),
false,
false,
/* vdex_fd= */ -1,
@@ -572,7 +555,6 @@
android::base::unique_fd zip_fd(open(dex_location.c_str(), O_RDONLY | O_CLOEXEC));
OatFileAssistant oat_file_assistant(dex_location.c_str(),
kRuntimeISA,
- default_context_.get(),
false,
false,
/* vdex_fd= */ -1,
@@ -597,10 +579,7 @@
GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kSpeed);
ASSERT_EQ(0, unlink(odex_location.c_str()));
- OatFileAssistant oat_file_assistant(dex_location.c_str(),
- kRuntimeISA,
- default_context_.get(),
- false);
+ OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
EXPECT_EQ(-OatFileAssistant::kNoDexOptNeeded,
GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kVerify));
@@ -629,10 +608,7 @@
ScratchFile vdex_file(vdex_location.c_str());
ScratchFile odex_file(odex_location.c_str());
- OatFileAssistant oat_file_assistant(dex_location.c_str(),
- kRuntimeISA,
- default_context_.get(),
- false);
+ OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
EXPECT_EQ(OatFileAssistant::kDex2OatFromScratch,
GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kSpeed));
}
@@ -658,10 +634,7 @@
ScopedNonWritable scoped_non_writable(dex_location);
ASSERT_TRUE(scoped_non_writable.IsSuccessful());
- OatFileAssistant oat_file_assistant(dex_location.c_str(),
- kRuntimeISA,
- default_context_.get(),
- false);
+ OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
EXPECT_EQ(OatFileAssistant::kDex2OatForFilter,
GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kSpeed));
@@ -684,10 +657,7 @@
ScopedNonWritable scoped_non_writable(dex_location);
ASSERT_TRUE(scoped_non_writable.IsSuccessful());
- OatFileAssistant oat_file_assistant(dex_location.c_str(),
- kRuntimeISA,
- default_context_.get(),
- false);
+ OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kSpeedProfile, false));
@@ -720,10 +690,7 @@
ScopedNonWritable scoped_non_writable(dex_location);
ASSERT_TRUE(scoped_non_writable.IsSuccessful());
- OatFileAssistant oat_file_assistant(dex_location.c_str(),
- kRuntimeISA,
- default_context_.get(),
- true);
+ 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.HasDexFiles());
@@ -759,10 +726,7 @@
ScopedNonWritable scoped_non_writable(dex_location);
ASSERT_TRUE(scoped_non_writable.IsSuccessful());
- OatFileAssistant oat_file_assistant(dex_location.c_str(),
- kRuntimeISA,
- default_context_.get(),
- true);
+ 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.HasDexFiles());
@@ -788,10 +752,7 @@
ScopedNonWritable scoped_non_writable(dex_location);
ASSERT_TRUE(scoped_non_writable.IsSuccessful());
- OatFileAssistant oat_file_assistant(dex_location.c_str(),
- kRuntimeISA,
- default_context_.get(),
- false);
+ OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
EXPECT_EQ(OatFileAssistant::kDex2OatFromScratch,
GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kExtract));
EXPECT_EQ(OatFileAssistant::kDex2OatFromScratch,
@@ -821,10 +782,7 @@
ASSERT_EQ(0, unlink(odex_location.c_str()));
Copy(GetDexSrc2(), dex_location);
- OatFileAssistant oat_file_assistant(dex_location.c_str(),
- kRuntimeISA,
- default_context_.get(),
- false);
+ OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
EXPECT_EQ(OatFileAssistant::kDex2OatFromScratch,
GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kSpeed));
@@ -841,10 +799,7 @@
ASSERT_EQ(0, unlink(odex_location.c_str()));
Copy(GetMultiDexSrc2(), dex_location);
- OatFileAssistant oat_file_assistant(dex_location.c_str(),
- kRuntimeISA,
- default_context_.get(),
- false);
+ OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
EXPECT_EQ(OatFileAssistant::kDex2OatFromScratch,
GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kSpeed));
@@ -869,10 +824,7 @@
ScopedNonWritable scoped_non_writable(dex_location);
ASSERT_TRUE(scoped_non_writable.IsSuccessful());
- OatFileAssistant oat_file_assistant(dex_location.c_str(),
- kRuntimeISA,
- default_context_.get(),
- false);
+ OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kExtract));
EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
@@ -914,10 +866,7 @@
ScopedNonWritable scoped_non_writable(dex_location);
ASSERT_TRUE(scoped_non_writable.IsSuccessful());
- OatFileAssistant oat_file_assistant(dex_location.c_str(),
- kRuntimeISA,
- default_context_.get(),
- false);
+ OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kExtract));
EXPECT_EQ(OatFileAssistant::kDex2OatForFilter,
@@ -939,10 +888,7 @@
GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kSpeed);
// Verify the status.
- OatFileAssistant oat_file_assistant(dex_location.c_str(),
- kRuntimeISA,
- default_context_.get(),
- false);
+ OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kExtract));
@@ -967,10 +913,7 @@
Copy(GetResourceOnlySrc1(), dex_location);
// Verify the status.
- OatFileAssistant oat_file_assistant(dex_location.c_str(),
- kRuntimeISA,
- default_context_.get(),
- true);
+ OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kSpeed));
@@ -1005,10 +948,7 @@
GenerateOatForTest(dex_location.c_str(), CompilerFilter::kSpeed);
// Verify things don't go bad.
- OatFileAssistant oat_file_assistant(dex_location.c_str(),
- kRuntimeISA,
- default_context_.get(),
- true);
+ OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kSpeed));
@@ -1038,10 +978,7 @@
GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kExtract);
// Verify the status.
- OatFileAssistant oat_file_assistant(dex_location.c_str(),
- kRuntimeISA,
- default_context_.get(),
- false);
+ OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kExtract));
@@ -1072,10 +1009,7 @@
ASSERT_TRUE(scoped_non_writable.IsSuccessful());
// Load the oat using an oat file assistant.
- OatFileAssistant oat_file_assistant(dex_location.c_str(),
- kRuntimeISA,
- default_context_.get(),
- true);
+ OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
ASSERT_TRUE(oat_file.get() != nullptr);
@@ -1103,10 +1037,7 @@
ASSERT_TRUE(scoped_non_writable.IsSuccessful());
// Load the oat using an oat file assistant.
- OatFileAssistant oat_file_assistant(dex_location.c_str(),
- kRuntimeISA,
- default_context_.get(),
- true);
+ OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
ASSERT_TRUE(oat_file.get() != nullptr);
@@ -1135,10 +1066,7 @@
GenerateOatForTest(dex_location.c_str(), CompilerFilter::kSpeed);
// Load the oat using an oat file assistant.
- OatFileAssistant oat_file_assistant(dex_location.c_str(),
- kRuntimeISA,
- default_context_.get(),
- false);
+ OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
ASSERT_TRUE(oat_file.get() != nullptr);
@@ -1191,10 +1119,7 @@
Copy(GetDexSrc1(), abs_dex_location);
std::string dex_location = MakePathRelative(abs_dex_location);
- OatFileAssistant oat_file_assistant(dex_location.c_str(),
- kRuntimeISA,
- default_context_.get(),
- true);
+ OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
EXPECT_EQ(OatFileAssistant::kDex2OatFromScratch,
@@ -1208,10 +1133,7 @@
TEST_F(OatFileAssistantTest, ShortDexLocation) {
std::string dex_location = "/xx";
- OatFileAssistant oat_file_assistant(dex_location.c_str(),
- kRuntimeISA,
- default_context_.get(),
- true);
+ OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
@@ -1227,10 +1149,7 @@
std::string dex_location = GetScratchDir() + "/LongDexExtension.jarx";
Copy(GetDexSrc1(), dex_location);
- OatFileAssistant oat_file_assistant(dex_location.c_str(),
- kRuntimeISA,
- default_context_.get(),
- false);
+ OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
EXPECT_EQ(OatFileAssistant::kDex2OatFromScratch,
GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kSpeed));
@@ -1336,7 +1255,7 @@
// Case: We have a DEX file and an ODEX file, and no OAT file,
// Expect: We should load the odex file executable.
-TEST_F(OatFileAssistantTest, LoadDexOdexNoOat) {
+TEST_F(DexoptTest, LoadDexOdexNoOat) {
std::string dex_location = GetScratchDir() + "/LoadDexOdexNoOat.jar";
std::string odex_location = GetOdexDir() + "/LoadDexOdexNoOat.odex";
@@ -1345,10 +1264,7 @@
GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kSpeed);
// Load the oat using an executable oat file assistant.
- OatFileAssistant oat_file_assistant(dex_location.c_str(),
- kRuntimeISA,
- default_context_.get(),
- true);
+ OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
ASSERT_TRUE(oat_file.get() != nullptr);
@@ -1360,7 +1276,7 @@
// Case: We have a MultiDEX file and an ODEX file, and no OAT file.
// Expect: We should load the odex file executable.
-TEST_F(OatFileAssistantTest, LoadMultiDexOdexNoOat) {
+TEST_F(DexoptTest, LoadMultiDexOdexNoOat) {
std::string dex_location = GetScratchDir() + "/LoadMultiDexOdexNoOat.jar";
std::string odex_location = GetOdexDir() + "/LoadMultiDexOdexNoOat.odex";
@@ -1369,10 +1285,7 @@
GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kSpeed);
// Load the oat using an executable oat file assistant.
- OatFileAssistant oat_file_assistant(dex_location.c_str(),
- kRuntimeISA,
- default_context_.get(),
- true);
+ OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
ASSERT_TRUE(oat_file.get() != nullptr);
@@ -1454,39 +1367,24 @@
{
std::unique_ptr<ClassLoaderContext> updated_context = ClassLoaderContext::Create(context_str);
ASSERT_TRUE(updated_context != nullptr);
- std::vector<int> context_fds;
- ASSERT_TRUE(updated_context->OpenDexFiles("", context_fds, /*only_read_checksums*/ true));
- OatFileAssistant oat_file_assistant(
- dex_location.c_str(), kRuntimeISA, updated_context.get(), false);
- // DexOptNeeded should advise compilation for filter when the context changes.
- EXPECT_EQ(-OatFileAssistant::kDex2OatForFilter,
- GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kDefaultCompilerFilter));
+ OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
+ // DexOptNeeded should advise compilation from scratch when the context changes.
+ EXPECT_EQ(OatFileAssistant::kDex2OatFromScratch,
+ GetDexOptNeeded(&oat_file_assistant,
+ CompilerFilter::kDefaultCompilerFilter,
+ updated_context));
}
{
std::unique_ptr<ClassLoaderContext> updated_context = ClassLoaderContext::Create(context_str);
ASSERT_TRUE(updated_context != nullptr);
- std::vector<int> context_fds;
- ASSERT_TRUE(updated_context->OpenDexFiles("", context_fds, /*only_read_checksums*/ true));
- OatFileAssistant oat_file_assistant(
- dex_location.c_str(), kRuntimeISA, updated_context.get(), false);
+ OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
// Now check that DexOptNeeded does not advise compilation if we only extracted the file.
args.push_back("--compiler-filter=extract");
ASSERT_TRUE(Dex2Oat(args, &error_msg)) << error_msg;
EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
- GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kExtract));
- }
- {
- std::unique_ptr<ClassLoaderContext> updated_context = ClassLoaderContext::Create(context_str);
- ASSERT_TRUE(updated_context != nullptr);
- std::vector<int> context_fds;
- ASSERT_TRUE(updated_context->OpenDexFiles("", context_fds, /*only_read_checksums*/ true));
- OatFileAssistant oat_file_assistant(
- dex_location.c_str(), kRuntimeISA, updated_context.get(), false);
- // Now check that DexOptNeeded does not advise compilation if we only verify the file.
- args.push_back("--compiler-filter=verify");
- ASSERT_TRUE(Dex2Oat(args, &error_msg)) << error_msg;
- EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
- GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kExtract));
+ GetDexOptNeeded(&oat_file_assistant,
+ CompilerFilter::kExtract,
+ updated_context));
}
}
diff --git a/runtime/oat_file_manager.cc b/runtime/oat_file_manager.cc
index 438ed6c..e485413 100644
--- a/runtime/oat_file_manager.cc
+++ b/runtime/oat_file_manager.cc
@@ -177,6 +177,40 @@
return oat_files;
}
+static bool ClassLoaderContextMatches(
+ const OatFile* oat_file,
+ const ClassLoaderContext* context,
+ /*out*/ std::string* error_msg) {
+ DCHECK(oat_file != nullptr);
+ DCHECK(error_msg != nullptr);
+ DCHECK(context != nullptr);
+
+ if (oat_file->IsBackedByVdexOnly()) {
+ // Only a vdex file, we don't depend on the class loader context.
+ return true;
+ }
+
+ if (!CompilerFilter::IsVerificationEnabled(oat_file->GetCompilerFilter())) {
+ // 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
+ // the oat file without addition checks
+ ClassLoaderContext::VerificationResult result = context->VerifyClassLoaderContextMatch(
+ oat_file->GetClassLoaderContext(),
+ /*verify_names=*/ true,
+ /*verify_checksums=*/ true);
+ switch (result) {
+ case ClassLoaderContext::VerificationResult::kMismatch:
+ return false;
+ case ClassLoaderContext::VerificationResult::kVerifies:
+ return true;
+ }
+ LOG(FATAL) << "Unreachable";
+}
+
bool OatFileManager::ShouldLoadAppImage(const OatFile* source_oat_file) const {
Runtime* const runtime = Runtime::Current();
return kEnableAppImage && (!runtime->IsJavaDebuggable() || source_oat_file->IsDebuggable());
@@ -199,18 +233,18 @@
Runtime* const runtime = Runtime::Current();
std::vector<std::unique_ptr<const DexFile>> dex_files;
- std::unique_ptr<ClassLoaderContext> context(
- ClassLoaderContext::CreateContextForClassLoader(class_loader, dex_elements));
// 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?";
- } else if (context != nullptr) {
+ } else {
+ std::unique_ptr<ClassLoaderContext> context(
+ ClassLoaderContext::CreateContextForClassLoader(class_loader, dex_elements));
+
OatFileAssistant oat_file_assistant(dex_location,
kRuntimeISA,
- context.get(),
runtime->GetOatFilesExecutable(),
only_use_system_oat_files_);
@@ -246,7 +280,22 @@
<< "optimization-status-location=" << odex_location
<< " best_oat_file-location=" << oat_file->GetLocation();
- if (oat_file != nullptr) {
+ const OatFile* source_oat_file = nullptr;
+ std::string error_msg;
+ bool class_loader_context_matches = false;
+ bool check_context = oat_file != nullptr && context != nullptr;
+ if (check_context) {
+ class_loader_context_matches =
+ ClassLoaderContextMatches(oat_file.get(),
+ context.get(),
+ /*out*/ &error_msg);
+ }
+ ScopedTrace context_results(StringPrintf(
+ "check_context=%s contex-ok=%s",
+ check_context ? "true" : "false",
+ class_loader_context_matches ? "true" : "false"));
+
+ if (class_loader_context_matches) {
// Load the dex files from the oat file.
bool added_image_space = false;
if (oat_file->IsExecutable()) {
@@ -318,7 +367,6 @@
// file as non-executable.
OatFileAssistant nonexecutable_oat_file_assistant(dex_location,
kRuntimeISA,
- context.get(),
/*load_executable=*/false,
only_use_system_oat_files_);
oat_file.reset(nonexecutable_oat_file_assistant.GetBestOatFile().release());
@@ -342,44 +390,46 @@
}
VLOG(class_linker) << "Registering " << oat_file->GetLocation();
- *out_oat_file = RegisterOatFile(std::move(oat_file));
- } else {
- // oat_file == nullptr
- // 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 (oat_file_assistant.GetBestStatus() == OatFileAssistant::kOatContextOutOfDate) {
- std::set<const DexFile*> already_exists_in_classpath =
- context->CheckForDuplicateDexFiles(MakeNonOwningPointerVector(dex_files));
- if (!already_exists_in_classpath.empty()) {
- ScopedTrace duplicate_dex_files("DuplicateDexFilesInContext");
- 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();
- }
+ source_oat_file = RegisterOatFile(std::move(oat_file));
+ *out_oat_file = source_oat_file;
+ } else if (!error_msg.empty()) {
+ LOG(WARNING) << error_msg;
+ }
- 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();
+ // 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()) {
+ ScopedTrace duplicate_dex_files("DuplicateDexFilesInContext");
+ 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();
}
}
}