diff options
| author | 2021-04-01 14:22:40 +0100 | |
|---|---|---|
| committer | 2021-04-15 12:30:01 +0000 | |
| commit | c8fe6517faf91b45683cddff3c15e08e489e12e9 (patch) | |
| tree | 10bf664496e680bbae0d22ff7da32dbbb923613f | |
| parent | 0c39de679bc4b647cfeb1c5c94c86d879848aa55 (diff) | |
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
| -rw-r--r-- | dexoptanalyzer/dexoptanalyzer.cc | 15 | ||||
| -rw-r--r-- | dexoptanalyzer/dexoptanalyzer_test.cc | 19 | ||||
| -rw-r--r-- | runtime/class_loader_context.cc | 8 | ||||
| -rw-r--r-- | runtime/native/dalvik_system_DexFile.cc | 25 | ||||
| -rw-r--r-- | runtime/oat_file_assistant.cc | 107 | ||||
| -rw-r--r-- | runtime/oat_file_assistant.h | 20 | ||||
| -rw-r--r-- | runtime/oat_file_assistant_test.cc | 248 | ||||
| -rw-r--r-- | runtime/oat_file_manager.cc | 132 |
8 files changed, 327 insertions, 247 deletions
diff --git a/dexoptanalyzer/dexoptanalyzer.cc b/dexoptanalyzer/dexoptanalyzer.cc index 5f501d6385..998f41a935 100644 --- a/dexoptanalyzer/dexoptanalyzer.cc +++ b/dexoptanalyzer/dexoptanalyzer.cc @@ -298,10 +298,23 @@ class DexoptAnalyzer final { 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 @@ class DexoptAnalyzer final { } 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 42be4735a2..ef6282aa1f 100644 --- a/dexoptanalyzer/dexoptanalyzer_test.cc +++ b/dexoptanalyzer/dexoptanalyzer_test.cc @@ -79,18 +79,23 @@ class DexoptAnalyzerTest : public DexoptTest { 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 b5ce122c95..228b95028a 100644 --- a/runtime/class_loader_context.cc +++ b/runtime/class_loader_context.cc @@ -412,7 +412,9 @@ bool ClassLoaderContext::OpenDexFiles(const std::string& classpath_dir, // 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 @@ std::unique_ptr<ClassLoaderContext> ClassLoaderContext::CreateContextForClassLoa 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 1c4adab426..f8ad7f1b7a 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 @@ static jint GetDexOptNeeded(JNIEnv* env, 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 @@ static jstring DexFile_getDexFileStatus(JNIEnv* env, 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 @@ static jboolean DexFile_isDexOptNeeded(JNIEnv* env, jclass, jstring javaFilename 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 @@ static jobjectArray DexFile_getDexFileOutputPaths(JNIEnv* env, } } - // 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 245ae36622..0bccc828bb 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 @@ std::ostream& operator << (std::ostream& stream, const OatFileAssistant::OatStat case OatFileAssistant::kOatUpToDate: stream << "kOatUpToDate"; break; - default: - UNREACHABLE(); + case OatFileAssistant::kOatContextOutOfDate: + stream << "kOaContextOutOfDate"; + break; } return stream; @@ -76,10 +78,12 @@ std::ostream& operator << (std::ostream& stream, const OatFileAssistant::OatStat 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, 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 @@ OatFileAssistant::OatFileAssistant(const char* dex_location, 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 @@ bool OatFileAssistant::IsInBootClassPath() { } 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 @@ OatFileAssistant::OatStatus OatFileAssistant::GivenOatFileStatus(const OatFile& return kOatDexOutOfDate; } + if (!ClassLoaderContextIsOkay(file)) { + return kOatContextOutOfDate; + } + return kOatUpToDate; } @@ -727,6 +734,7 @@ bool OatFileAssistant::OatFileInfo::IsUseable() { switch (Status()) { case kOatCannotOpen: case kOatDexOutOfDate: + case kOatContextOutOfDate: case kOatBootImageOutOfDate: return false; case kOatUpToDate: return true; @@ -752,29 +760,17 @@ OatFileAssistant::OatStatus OatFileAssistant::OatFileInfo::Status() { 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); - - // 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 (IsUseable()) { + return CompilerFilterIsOkay(target, profile_changed, downgrade) + ? kNoDexOptNeeded + : kDex2OatForFilter; + } - if (Status() == kOatBootImageOutOfDate) { - return kDex2OatForBootImage; - } + if (Status() == kOatBootImageOutOfDate) { + return kDex2OatForBootImage; } if (oat_file_assistant_->HasDexFiles()) { @@ -887,51 +883,36 @@ bool OatFileAssistant::OatFileInfo::CompilerFilterIsOkay( 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; - } - - 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; + if (context_ == nullptr) { + // When no class loader context is provided (which happens for deprecated + // DexFile APIs), just assume it is OK. + return true; } - 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 @@ void OatFileAssistant::GetOptimizationStatus( 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 @@ void OatFileAssistant::GetOptimizationStatus( *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 e771dcc817..50b54afa93 100644 --- a/runtime/oat_file_assistant.h +++ b/runtime/oat_file_assistant.h @@ -80,6 +80,10 @@ class OatFileAssistant { // 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 @@ class OatFileAssistant { // 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 @@ class OatFileAssistant { // 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 @@ class OatFileAssistant { // 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 @@ class OatFileAssistant { // 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 @@ class OatFileAssistant { // 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 @@ class OatFileAssistant { // 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 @@ class OatFileAssistant { // 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 @@ class OatFileAssistant { 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 16d3ce05a5..5631e12a90 100644 --- a/runtime/oat_file_assistant_test.cc +++ b/runtime/oat_file_assistant_test.cc @@ -98,32 +98,24 @@ class OatFileAssistantTest : public DexoptTest { } } - 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 @@ TEST_F(OatFileAssistantTest, RelativeEncodedDexLocation) { 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 @@ TEST_F(OatFileAssistantTest, MakeUpToDateWithContext) { 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 @@ TEST_F(OatFileAssistantTest, MakeUpToDateWithContext) { 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 @@ TEST_F(OatFileAssistantTest, GetDexOptNeededWithUpToDateContextRelative) { 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 @@ TEST_F(OatFileAssistantTest, DexNoOat) { 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, DexNoOat) { 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 @@ TEST_F(OatFileAssistantTest, OdexUpToDate) { // 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 @@ TEST_F(OatFileAssistantTest, OdexUpToDatePartialBootImage) { // 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 @@ TEST_F(OatFileAssistantTest, OdexUpToDateSymLink) { 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 @@ TEST_F(OatFileAssistantTest, OatUpToDate) { 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 @@ TEST_F(OatFileAssistantTest, GetDexOptNeededWithFd) { OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, + default_context_.get(), false, false, vdex_fd.get(), @@ -496,6 +511,7 @@ TEST_F(OatFileAssistantTest, GetDexOptNeededWithInvalidOdexFd) { OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, + default_context_.get(), false, false, vdex_fd.get(), @@ -531,6 +547,7 @@ TEST_F(OatFileAssistantTest, GetDexOptNeededWithInvalidVdexFd) { OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, + default_context_.get(), false, false, /* vdex_fd= */ -1, @@ -555,6 +572,7 @@ TEST_F(OatFileAssistantTest, GetDexOptNeededWithInvalidOdexVdexFd) { 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 @@ TEST_F(OatFileAssistantTest, VdexUpToDateNoOdex) { 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 @@ TEST_F(OatFileAssistantTest, EmptyVdexOdex) { 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 @@ TEST_F(OatFileAssistantTest, VdexUpToDateNoOat) { 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 @@ TEST_F(OatFileAssistantTest, ProfileOatUpToDate) { 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 @@ TEST_F(OatFileAssistantTest, MultiDexOatUpToDate) { 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 @@ TEST_F(OatFileAssistantTest, MultiDexNonMainOutOfDate) { 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 @@ TEST_F(OatFileAssistantTest, OatDexOutOfDate) { 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 @@ TEST_F(OatFileAssistantTest, VdexDexOutOfDate) { 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 @@ TEST_F(OatFileAssistantTest, VdexMultiDexNonMainOutOfDate) { 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 @@ TEST_F(OatFileAssistantTest, OatImageOutOfDate) { 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 @@ TEST_F(OatFileAssistantTest, OatVerifyAtRuntimeImageOutOfDate) { 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 @@ TEST_F(OatFileAssistantTest, DexOdexNoOat) { 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 @@ TEST_F(OatFileAssistantTest, ResourceOnlyDex) { 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 @@ TEST_F(OatFileAssistantTest, OdexOatOverlap) { 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 @@ TEST_F(OatFileAssistantTest, DexVerifyAtRuntimeOdexNoOat) { 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 @@ TEST_F(OatFileAssistantTest, LoadOatUpToDate) { 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 @@ TEST_F(OatFileAssistantTest, LoadExecInterpretOnlyOatUpToDate) { 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 @@ TEST_F(OatFileAssistantTest, LoadNoExecOatUpToDate) { 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 @@ TEST_F(OatFileAssistantTest, NonAbsoluteDexLocation) { 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, NonAbsoluteDexLocation) { 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 @@ TEST_F(OatFileAssistantTest, LongDexExtension) { 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 @@ TEST_F(OatFileAssistantTest, RaceToGenerate) { // 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 @@ TEST_F(DexoptTest, LoadDexOdexNoOat) { 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 @@ TEST_F(DexoptTest, LoadDexOdexNoOat) { // 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 @@ TEST_F(DexoptTest, LoadMultiDexOdexNoOat) { 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 @@ TEST_F(OatFileAssistantTest, GetDexOptNeededWithOutOfDateContext) { { 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 e4854135f1..438ed6c12f 100644 --- a/runtime/oat_file_manager.cc +++ b/runtime/oat_file_manager.cc @@ -177,40 +177,6 @@ std::vector<const OatFile*> OatFileManager::RegisterImageOatFiles( 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 @@ std::vector<std::unique_ptr<const DexFile>> OatFileManager::OpenDexFilesFromOat( 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 @@ std::vector<std::unique_ptr<const DexFile>> OatFileManager::OpenDexFilesFromOat( << "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 @@ std::vector<std::unique_ptr<const DexFile>> OatFileManager::OpenDexFilesFromOat( // 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 @@ std::vector<std::unique_ptr<const DexFile>> OatFileManager::OpenDexFilesFromOat( } 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); + } - 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(); } - - // 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(); } } } |