Integrate ClassLoaderContext check in OatFileAssistant::GetBestOatFile.
This reduces some code duplication between
OatFileManager::OpenDexFilesFromOat and GetDexoptNeeded.
It also gives the chance for OatFileAssistant and GetDexoptNeeded to
find the real best oat file.
Test: test.py
Bug: 176960283
Change-Id: Id366aef7a9e91833d8edaea965abda4cfdcd8455
diff --git a/dexoptanalyzer/dexoptanalyzer.cc b/dexoptanalyzer/dexoptanalyzer.cc
index 5f501d6..998f41a 100644
--- a/dexoptanalyzer/dexoptanalyzer.cc
+++ b/dexoptanalyzer/dexoptanalyzer.cc
@@ -298,10 +298,23 @@
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_,
@@ -314,8 +327,6 @@
}
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 42be473..ef6282a 100644
--- a/dexoptanalyzer/dexoptanalyzer_test.cc
+++ b/dexoptanalyzer/dexoptanalyzer_test.cc
@@ -79,18 +79,23 @@
bool assume_profile_changed = false,
bool downgrade = false,
const char* class_loader_context = "PCL[]") {
- 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, /*load_executable=*/ false);
- std::vector<int> context_fds;
-
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);
int assistantResult = oat_file_assistant.GetDexOptNeeded(
- compiler_filter, context.get(), context_fds, assume_profile_changed, downgrade);
+ compiler_filter, assume_profile_changed, downgrade);
EXPECT_EQ(assistantResult, dexoptanalyzerResult);
}
};
diff --git a/runtime/class_loader_context.cc b/runtime/class_loader_context.cc
index b5ce122..228b950 100644
--- a/runtime/class_loader_context.cc
+++ b/runtime/class_loader_context.cc
@@ -412,7 +412,9 @@
// no dex files. So that we can distinguish the real failures...
const ArtDexFileLoader dex_file_loader;
std::vector<ClassLoaderInfo*> work_list;
- CHECK(class_loader_chain_ != nullptr);
+ if (class_loader_chain_ == nullptr) {
+ return true;
+ }
work_list.push_back(class_loader_chain_.get());
size_t dex_file_index = 0;
while (!work_list.empty()) {
@@ -1155,7 +1157,9 @@
jobjectArray dex_elements) {
ScopedTrace trace(__FUNCTION__);
- CHECK(class_loader != nullptr);
+ if (class_loader == nullptr) {
+ return 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 1c4adab..f8ad7f1 100644
--- a/runtime/native/dalvik_system_DexFile.cc
+++ b/runtime/native/dalvik_system_DexFile.cc
@@ -18,6 +18,7 @@
#include <sstream>
+#include "android-base/file.h"
#include "android-base/stringprintf.h"
#include "base/casts.h"
@@ -541,22 +542,26 @@
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, false);
+ OatFileAssistant oat_file_assistant(filename,
+ target_instruction_set,
+ context.get(),
+ /* load_executable= */ 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);
}
@@ -584,7 +589,9 @@
return nullptr;
}
- OatFileAssistant oat_file_assistant(filename.c_str(), target_instruction_set,
+ OatFileAssistant oat_file_assistant(filename.c_str(),
+ target_instruction_set,
+ /* context= */ nullptr,
/* load_executable= */ false);
return env->NewStringUTF(oat_file_assistant.GetStatusDump().c_str());
}
@@ -691,7 +698,10 @@
return JNI_FALSE;
}
- OatFileAssistant oat_file_assistant(filename, kRuntimeISA, false);
+ OatFileAssistant oat_file_assistant(filename,
+ kRuntimeISA,
+ /* context= */ nullptr,
+ /* load_executable= */ false);
return oat_file_assistant.IsUpToDate() ? JNI_FALSE : JNI_TRUE;
}
@@ -828,10 +838,11 @@
}
}
- // If did not find a boot classpath oat file, lookup the oat file for an app.
+ // If we 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 245ae36..0bccc82 100644
--- a/runtime/oat_file_assistant.cc
+++ b/runtime/oat_file_assistant.cc
@@ -21,6 +21,7 @@
#include <sys/stat.h>
#include "zlib.h"
+#include "android-base/file.h"
#include "android-base/stringprintf.h"
#include "android-base/strings.h"
@@ -67,8 +68,9 @@
case OatFileAssistant::kOatUpToDate:
stream << "kOatUpToDate";
break;
- default:
- UNREACHABLE();
+ case OatFileAssistant::kOatContextOutOfDate:
+ stream << "kOaContextOutOfDate";
+ break;
}
return stream;
@@ -76,10 +78,12 @@
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,
@@ -89,12 +93,14 @@
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)
- : isa_(isa),
+ : context_(context),
+ isa_(isa),
load_executable_(load_executable),
only_load_system_executable_(only_load_system_executable),
odex_(this, /*is_oat_location=*/ false),
@@ -103,6 +109,7 @@
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
@@ -192,14 +199,10 @@
}
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) {
@@ -443,6 +446,10 @@
return kOatDexOutOfDate;
}
+ if (!ClassLoaderContextIsOkay(file)) {
+ return kOatContextOutOfDate;
+ }
+
return kOatUpToDate;
}
@@ -727,6 +734,7 @@
switch (Status()) {
case kOatCannotOpen:
case kOatDexOutOfDate:
+ case kOatContextOutOfDate:
case kOatBootImageOutOfDate: return false;
case kOatUpToDate: return true;
@@ -752,29 +760,17 @@
OatFileAssistant::DexOptNeeded OatFileAssistant::OatFileInfo::GetDexOptNeeded(
CompilerFilter::Filter target,
- ClassLoaderContext* context,
- const std::vector<int>& context_fds,
bool profile_changed,
bool downgrade) {
- bool filter_okay = CompilerFilterIsOkay(target, profile_changed, downgrade);
- bool class_loader_context_okay = ClassLoaderContextIsOkay(context, context_fds);
+ if (IsUseable()) {
+ return CompilerFilterIsOkay(target, profile_changed, downgrade)
+ ? kNoDexOptNeeded
+ : kDex2OatForFilter;
+ }
- // 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 (Status() == kOatBootImageOutOfDate) {
+ return kDex2OatForBootImage;
}
if (oat_file_assistant_->HasDexFiles()) {
@@ -887,51 +883,36 @@
CompilerFilter::IsAsGoodAs(current, target);
}
-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()) {
+bool OatFileAssistant::ClassLoaderContextIsOkay(const OatFile& oat_file) const {
+ if (oat_file.IsBackedByVdexOnly()) {
// Only a vdex file, we don't depend on the class loader context.
return true;
}
- if (!CompilerFilter::IsVerificationEnabled(file->GetCompilerFilter())) {
+ if (!CompilerFilter::IsVerificationEnabled(oat_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) {
- // 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;
+ if (context_ == nullptr) {
+ // When no class loader context is provided (which happens for deprecated
+ // DexFile APIs), just assume it is OK.
+ 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) {
+ 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 "
- << file->GetClassLoaderContext()
- << ". The expected context is " << context->EncodeContextForOatFile(classpath_dir);
+ << oat_file.GetClassLoaderContext()
+ << ". The expected context is "
+ << context_->EncodeContextForOatFile(android::base::Dirname(dex_location_));
+ return false;
}
- return result;
+ return true;
}
bool OatFileAssistant::OatFileInfo::IsExecutable() {
@@ -983,7 +964,10 @@
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, /*load_executable=*/ false);
+ OatFileAssistant oat_file_assistant(filename.c_str(),
+ isa,
+ /* context= */ nullptr,
+ /*load_executable=*/ false);
std::string out_odex_location; // unused
std::string out_odex_status; // unused
oat_file_assistant.GetOptimizationStatus(
@@ -1038,6 +1022,11 @@
*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 e771dcc..50b54af 100644
--- a/runtime/oat_file_assistant.h
+++ b/runtime/oat_file_assistant.h
@@ -80,6 +80,10 @@
// 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,
@@ -107,6 +111,7 @@
// 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);
@@ -115,6 +120,7 @@
// 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,
@@ -142,8 +148,6 @@
// 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);
@@ -227,6 +231,10 @@
// 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.
@@ -262,6 +270,8 @@
// 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:
@@ -294,8 +304,6 @@
// 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);
@@ -338,8 +346,6 @@
// 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.
//
@@ -407,6 +413,8 @@
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 16d3ce0..5631e12 100644
--- a/runtime/oat_file_assistant_test.cc
+++ b/runtime/oat_file_assistant_test.cc
@@ -98,32 +98,24 @@
}
}
- 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 {
@@ -181,7 +173,10 @@
ASSERT_TRUE(Dex2Oat(args, &error_msg)) << error_msg;
// Verify we can load both dex files.
- OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
+ OatFileAssistant oat_file_assistant(dex_location.c_str(),
+ kRuntimeISA,
+ default_context_.get(),
+ true);
std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
ASSERT_TRUE(oat_file.get() != nullptr);
@@ -198,13 +193,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);
@@ -213,7 +208,8 @@
ASSERT_TRUE(Dex2Oat(args, &error_msg)) << error_msg;
std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
- EXPECT_NE(nullptr, oat_file.get());
+ ASSERT_NE(nullptr, oat_file.get());
+ ASSERT_NE(nullptr, oat_file->GetOatHeader().GetStoreValueByKey(OatHeader::kClassPathKey));
EXPECT_EQ(context->EncodeContextForOatFile(""),
oat_file->GetOatHeader().GetStoreValueByKey(OatHeader::kClassPathKey));
}
@@ -225,27 +221,27 @@
Copy(GetDexSrc1(), dex_location);
Copy(GetDexSrc2(), context_location);
- OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
+ // 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));
- 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,
+ relative_context.get(),
+ false);
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=" + context_str);
+ args.push_back("--class-loader-context=PCL[" + context_location + "]");
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,
- relative_context));
+ GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kDefaultCompilerFilter));
}
// Case: We have a DEX file, but no OAT file for it.
@@ -254,7 +250,10 @@
std::string dex_location = GetScratchDir() + "/DexNoOat.jar";
Copy(GetDexSrc1(), dex_location);
- OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
+ OatFileAssistant oat_file_assistant(dex_location.c_str(),
+ kRuntimeISA,
+ default_context_.get(),
+ false);
EXPECT_EQ(OatFileAssistant::kDex2OatFromScratch,
GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kExtract));
@@ -283,7 +282,10 @@
TEST_F(OatFileAssistantTest, NoDexNoOat) {
std::string dex_location = GetScratchDir() + "/NoDexNoOat.jar";
- OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
+ OatFileAssistant oat_file_assistant(dex_location.c_str(),
+ kRuntimeISA,
+ default_context_.get(),
+ true);
EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kSpeed));
@@ -304,7 +306,10 @@
// Force the use of oat location by making the dex parent not writable.
OatFileAssistant oat_file_assistant(
- dex_location.c_str(), kRuntimeISA, /*load_executable=*/ false);
+ dex_location.c_str(),
+ kRuntimeISA,
+ default_context_.get(),
+ /*load_executable=*/ false);
EXPECT_EQ(-OatFileAssistant::kNoDexOptNeeded,
GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kSpeed));
@@ -341,7 +346,10 @@
// Force the use of oat location by making the dex parent not writable.
OatFileAssistant oat_file_assistant(
- dex_location.c_str(), kRuntimeISA, /*load_executable=*/ false);
+ dex_location.c_str(),
+ kRuntimeISA,
+ default_context_.get(),
+ /*load_executable=*/ false);
EXPECT_EQ(-OatFileAssistant::kNoDexOptNeeded,
GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kSpeed));
@@ -381,7 +389,10 @@
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, false);
+ OatFileAssistant oat_file_assistant(dex_location.c_str(),
+ kRuntimeISA,
+ default_context_.get(),
+ false);
EXPECT_EQ(-OatFileAssistant::kNoDexOptNeeded,
GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kSpeed));
@@ -415,7 +426,10 @@
ScopedNonWritable scoped_non_writable(dex_location);
ASSERT_TRUE(scoped_non_writable.IsSuccessful());
- OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
+ OatFileAssistant oat_file_assistant(dex_location.c_str(),
+ kRuntimeISA,
+ default_context_.get(),
+ false);
EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kSpeed));
@@ -458,6 +472,7 @@
OatFileAssistant oat_file_assistant(dex_location.c_str(),
kRuntimeISA,
+ default_context_.get(),
false,
false,
vdex_fd.get(),
@@ -496,6 +511,7 @@
OatFileAssistant oat_file_assistant(dex_location.c_str(),
kRuntimeISA,
+ default_context_.get(),
false,
false,
vdex_fd.get(),
@@ -531,6 +547,7 @@
OatFileAssistant oat_file_assistant(dex_location.c_str(),
kRuntimeISA,
+ default_context_.get(),
false,
false,
/* vdex_fd= */ -1,
@@ -555,6 +572,7 @@
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,
@@ -579,7 +597,10 @@
GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kSpeed);
ASSERT_EQ(0, unlink(odex_location.c_str()));
- OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
+ OatFileAssistant oat_file_assistant(dex_location.c_str(),
+ kRuntimeISA,
+ default_context_.get(),
+ false);
EXPECT_EQ(-OatFileAssistant::kNoDexOptNeeded,
GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kVerify));
@@ -608,7 +629,10 @@
ScratchFile vdex_file(vdex_location.c_str());
ScratchFile odex_file(odex_location.c_str());
- OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
+ OatFileAssistant oat_file_assistant(dex_location.c_str(),
+ kRuntimeISA,
+ default_context_.get(),
+ false);
EXPECT_EQ(OatFileAssistant::kDex2OatFromScratch,
GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kSpeed));
}
@@ -634,7 +658,10 @@
ScopedNonWritable scoped_non_writable(dex_location);
ASSERT_TRUE(scoped_non_writable.IsSuccessful());
- OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
+ OatFileAssistant oat_file_assistant(dex_location.c_str(),
+ kRuntimeISA,
+ default_context_.get(),
+ false);
EXPECT_EQ(OatFileAssistant::kDex2OatForFilter,
GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kSpeed));
@@ -657,7 +684,10 @@
ScopedNonWritable scoped_non_writable(dex_location);
ASSERT_TRUE(scoped_non_writable.IsSuccessful());
- OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
+ OatFileAssistant oat_file_assistant(dex_location.c_str(),
+ kRuntimeISA,
+ default_context_.get(),
+ false);
EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kSpeedProfile, false));
@@ -690,7 +720,10 @@
ScopedNonWritable scoped_non_writable(dex_location);
ASSERT_TRUE(scoped_non_writable.IsSuccessful());
- OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
+ OatFileAssistant oat_file_assistant(dex_location.c_str(),
+ kRuntimeISA,
+ default_context_.get(),
+ true);
EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kSpeed));
EXPECT_TRUE(oat_file_assistant.HasDexFiles());
@@ -726,7 +759,10 @@
ScopedNonWritable scoped_non_writable(dex_location);
ASSERT_TRUE(scoped_non_writable.IsSuccessful());
- OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
+ OatFileAssistant oat_file_assistant(dex_location.c_str(),
+ kRuntimeISA,
+ default_context_.get(),
+ true);
EXPECT_EQ(OatFileAssistant::kDex2OatFromScratch,
GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kSpeed));
EXPECT_TRUE(oat_file_assistant.HasDexFiles());
@@ -752,7 +788,10 @@
ScopedNonWritable scoped_non_writable(dex_location);
ASSERT_TRUE(scoped_non_writable.IsSuccessful());
- OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
+ OatFileAssistant oat_file_assistant(dex_location.c_str(),
+ kRuntimeISA,
+ default_context_.get(),
+ false);
EXPECT_EQ(OatFileAssistant::kDex2OatFromScratch,
GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kExtract));
EXPECT_EQ(OatFileAssistant::kDex2OatFromScratch,
@@ -782,7 +821,10 @@
ASSERT_EQ(0, unlink(odex_location.c_str()));
Copy(GetDexSrc2(), dex_location);
- OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
+ OatFileAssistant oat_file_assistant(dex_location.c_str(),
+ kRuntimeISA,
+ default_context_.get(),
+ false);
EXPECT_EQ(OatFileAssistant::kDex2OatFromScratch,
GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kSpeed));
@@ -799,7 +841,10 @@
ASSERT_EQ(0, unlink(odex_location.c_str()));
Copy(GetMultiDexSrc2(), dex_location);
- OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
+ OatFileAssistant oat_file_assistant(dex_location.c_str(),
+ kRuntimeISA,
+ default_context_.get(),
+ false);
EXPECT_EQ(OatFileAssistant::kDex2OatFromScratch,
GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kSpeed));
@@ -824,7 +869,10 @@
ScopedNonWritable scoped_non_writable(dex_location);
ASSERT_TRUE(scoped_non_writable.IsSuccessful());
- OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
+ OatFileAssistant oat_file_assistant(dex_location.c_str(),
+ kRuntimeISA,
+ default_context_.get(),
+ false);
EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kExtract));
EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
@@ -866,7 +914,10 @@
ScopedNonWritable scoped_non_writable(dex_location);
ASSERT_TRUE(scoped_non_writable.IsSuccessful());
- OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
+ OatFileAssistant oat_file_assistant(dex_location.c_str(),
+ kRuntimeISA,
+ default_context_.get(),
+ false);
EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kExtract));
EXPECT_EQ(OatFileAssistant::kDex2OatForFilter,
@@ -888,7 +939,10 @@
GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kSpeed);
// Verify the status.
- OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
+ OatFileAssistant oat_file_assistant(dex_location.c_str(),
+ kRuntimeISA,
+ default_context_.get(),
+ false);
EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kExtract));
@@ -913,7 +967,10 @@
Copy(GetResourceOnlySrc1(), dex_location);
// Verify the status.
- OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
+ OatFileAssistant oat_file_assistant(dex_location.c_str(),
+ kRuntimeISA,
+ default_context_.get(),
+ true);
EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kSpeed));
@@ -948,7 +1005,10 @@
GenerateOatForTest(dex_location.c_str(), CompilerFilter::kSpeed);
// Verify things don't go bad.
- OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
+ OatFileAssistant oat_file_assistant(dex_location.c_str(),
+ kRuntimeISA,
+ default_context_.get(),
+ true);
EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kSpeed));
@@ -978,7 +1038,10 @@
GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kExtract);
// Verify the status.
- OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
+ OatFileAssistant oat_file_assistant(dex_location.c_str(),
+ kRuntimeISA,
+ default_context_.get(),
+ false);
EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kExtract));
@@ -1009,7 +1072,10 @@
ASSERT_TRUE(scoped_non_writable.IsSuccessful());
// Load the oat using an oat file assistant.
- OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
+ OatFileAssistant oat_file_assistant(dex_location.c_str(),
+ kRuntimeISA,
+ default_context_.get(),
+ true);
std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
ASSERT_TRUE(oat_file.get() != nullptr);
@@ -1037,7 +1103,10 @@
ASSERT_TRUE(scoped_non_writable.IsSuccessful());
// Load the oat using an oat file assistant.
- OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
+ OatFileAssistant oat_file_assistant(dex_location.c_str(),
+ kRuntimeISA,
+ default_context_.get(),
+ true);
std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
ASSERT_TRUE(oat_file.get() != nullptr);
@@ -1066,7 +1135,10 @@
GenerateOatForTest(dex_location.c_str(), CompilerFilter::kSpeed);
// Load the oat using an oat file assistant.
- OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
+ OatFileAssistant oat_file_assistant(dex_location.c_str(),
+ kRuntimeISA,
+ default_context_.get(),
+ false);
std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
ASSERT_TRUE(oat_file.get() != nullptr);
@@ -1119,7 +1191,10 @@
Copy(GetDexSrc1(), abs_dex_location);
std::string dex_location = MakePathRelative(abs_dex_location);
- OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
+ OatFileAssistant oat_file_assistant(dex_location.c_str(),
+ kRuntimeISA,
+ default_context_.get(),
+ true);
EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
EXPECT_EQ(OatFileAssistant::kDex2OatFromScratch,
@@ -1133,7 +1208,10 @@
TEST_F(OatFileAssistantTest, ShortDexLocation) {
std::string dex_location = "/xx";
- OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, true);
+ OatFileAssistant oat_file_assistant(dex_location.c_str(),
+ kRuntimeISA,
+ default_context_.get(),
+ true);
EXPECT_FALSE(oat_file_assistant.IsInBootClassPath());
EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded,
@@ -1149,7 +1227,10 @@
std::string dex_location = GetScratchDir() + "/LongDexExtension.jarx";
Copy(GetDexSrc1(), dex_location);
- OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
+ OatFileAssistant oat_file_assistant(dex_location.c_str(),
+ kRuntimeISA,
+ default_context_.get(),
+ false);
EXPECT_EQ(OatFileAssistant::kDex2OatFromScratch,
GetDexOptNeeded(&oat_file_assistant, CompilerFilter::kSpeed));
@@ -1255,7 +1336,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(DexoptTest, LoadDexOdexNoOat) {
+TEST_F(OatFileAssistantTest, LoadDexOdexNoOat) {
std::string dex_location = GetScratchDir() + "/LoadDexOdexNoOat.jar";
std::string odex_location = GetOdexDir() + "/LoadDexOdexNoOat.odex";
@@ -1264,7 +1345,10 @@
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, true);
+ OatFileAssistant oat_file_assistant(dex_location.c_str(),
+ kRuntimeISA,
+ default_context_.get(),
+ true);
std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
ASSERT_TRUE(oat_file.get() != nullptr);
@@ -1276,7 +1360,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(DexoptTest, LoadMultiDexOdexNoOat) {
+TEST_F(OatFileAssistantTest, LoadMultiDexOdexNoOat) {
std::string dex_location = GetScratchDir() + "/LoadMultiDexOdexNoOat.jar";
std::string odex_location = GetOdexDir() + "/LoadMultiDexOdexNoOat.odex";
@@ -1285,7 +1369,10 @@
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, true);
+ OatFileAssistant oat_file_assistant(dex_location.c_str(),
+ kRuntimeISA,
+ default_context_.get(),
+ true);
std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile();
ASSERT_TRUE(oat_file.get() != nullptr);
@@ -1367,24 +1454,39 @@
{
std::unique_ptr<ClassLoaderContext> updated_context = ClassLoaderContext::Create(context_str);
ASSERT_TRUE(updated_context != nullptr);
- 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::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));
}
{
std::unique_ptr<ClassLoaderContext> updated_context = ClassLoaderContext::Create(context_str);
ASSERT_TRUE(updated_context != nullptr);
- OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false);
+ 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 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,
- updated_context));
+ 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));
}
}
diff --git a/runtime/oat_file_manager.cc b/runtime/oat_file_manager.cc
index e485413..438ed6c 100644
--- a/runtime/oat_file_manager.cc
+++ b/runtime/oat_file_manager.cc
@@ -177,40 +177,6 @@
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());
@@ -233,18 +199,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 {
- std::unique_ptr<ClassLoaderContext> context(
- ClassLoaderContext::CreateContextForClassLoader(class_loader, dex_elements));
-
+ } else if (context != nullptr) {
OatFileAssistant oat_file_assistant(dex_location,
kRuntimeISA,
+ context.get(),
runtime->GetOatFilesExecutable(),
only_use_system_oat_files_);
@@ -280,22 +246,7 @@
<< "optimization-status-location=" << odex_location
<< " best_oat_file-location=" << oat_file->GetLocation();
- 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) {
+ if (oat_file != nullptr) {
// Load the dex files from the oat file.
bool added_image_space = false;
if (oat_file->IsExecutable()) {
@@ -367,6 +318,7 @@
// 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());
@@ -390,46 +342,44 @@
}
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;
- }
+ *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();
+ }
- // 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();
}
-
- 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();
}
}
}