diff options
author | android-build-team Robot <android-build-team-robot@google.com> | 2017-09-17 07:34:57 +0000 |
---|---|---|
committer | android-build-team Robot <android-build-team-robot@google.com> | 2017-09-17 07:34:57 +0000 |
commit | 171693533c0d80eb7d5d88edb75db691582a54ad (patch) | |
tree | a8f719af7bc66652f037e9ab15661afaa2b8e446 | |
parent | c831b1889651396ddf27a1ef9a944ecff21f030f (diff) | |
parent | b6471ac0749b58a68954a61c71b4695b6b86449d (diff) | |
download | art-171693533c0d80eb7d5d88edb75db691582a54ad.tar.gz |
release-request-1f2fcfef-9736-44dc-8628-3ba96dac60db-for-git_oc-mr1-release-4343541 snap-temp-L73700000103533431
Change-Id: I57beb1d141ca8bd70d561c053e3235f2d6c929be
-rw-r--r-- | dexoptanalyzer/dexoptanalyzer.cc | 2 | ||||
-rw-r--r-- | runtime/class_loader_context.cc | 32 | ||||
-rw-r--r-- | runtime/class_loader_context.h | 8 | ||||
-rw-r--r-- | runtime/class_loader_context_test.cc | 82 | ||||
-rw-r--r-- | runtime/native/dalvik_system_DexFile.cc | 2 | ||||
-rw-r--r-- | runtime/oat_file.cc | 4 | ||||
-rw-r--r-- | runtime/oat_file.h | 2 | ||||
-rw-r--r-- | runtime/oat_file_assistant.cc | 97 | ||||
-rw-r--r-- | runtime/oat_file_assistant.h | 13 | ||||
-rw-r--r-- | runtime/oat_file_assistant_test.cc | 62 | ||||
-rw-r--r-- | runtime/oat_file_manager.cc | 12 |
11 files changed, 218 insertions, 98 deletions
diff --git a/dexoptanalyzer/dexoptanalyzer.cc b/dexoptanalyzer/dexoptanalyzer.cc index fc72bbdb87..51a67ca45e 100644 --- a/dexoptanalyzer/dexoptanalyzer.cc +++ b/dexoptanalyzer/dexoptanalyzer.cc @@ -229,6 +229,8 @@ class DexoptAnalyzer FINAL { if (oat_file_assistant.IsInBootClassPath()) { return kNoDexOptNeeded; } + + // TODO(calin): Pass the class loader context as an argument to dexoptanalyzer. b/62269291. int dexoptNeeded = oat_file_assistant.GetDexOptNeeded( compiler_filter_, assume_profile_changed_, downgrade_); diff --git a/runtime/class_loader_context.cc b/runtime/class_loader_context.cc index 6084b849f7..ef274b199b 100644 --- a/runtime/class_loader_context.cc +++ b/runtime/class_loader_context.cc @@ -187,7 +187,10 @@ bool ClassLoaderContext::Parse(const std::string& spec, bool parse_checksums) { // Opens requested class path files and appends them to opened_dex_files. If the dex files have // been stripped, this opens them from their oat files (which get added to opened_oat_files). bool ClassLoaderContext::OpenDexFiles(InstructionSet isa, const std::string& classpath_dir) { - CHECK(!dex_files_open_attempted_) << "OpenDexFiles should not be called twice"; + if (dex_files_open_attempted_) { + // Do not attempt to re-open the files if we already tried. + return dex_files_open_result_; + } dex_files_open_attempted_ = true; // Assume we can open all dex files. If not, we will set this to false as we go. @@ -203,6 +206,7 @@ bool ClassLoaderContext::OpenDexFiles(InstructionSet isa, const std::string& cla // TODO(calin): Refine the dex opening interface to be able to tell if an archive contains // no dex files. So that we can distinguish the real failures... for (ClassLoaderInfo& info : class_loader_chain_) { + size_t opened_dex_files_index = info.opened_dex_files.size(); for (const std::string& cp_elem : info.classpath) { // If path is relative, append it to the provided base directory. std::string raw_location = cp_elem; @@ -249,6 +253,23 @@ bool ClassLoaderContext::OpenDexFiles(InstructionSet isa, const std::string& cla } } } + + // We finished opening the dex files from the classpath. + // Now update the classpath and the checksum with the locations of the dex files. + // + // We do this because initially the classpath contains the paths of the dex files; and + // some of them might be multi-dexes. So in order to have a consistent view we replace all the + // file paths with the actual dex locations being loaded. + // This will allow the context to VerifyClassLoaderContextMatch which expects or multidex + // location in the class paths. + // Note that this will also remove the paths that could not be opened. + info.classpath.clear(); + info.checksums.clear(); + for (size_t k = opened_dex_files_index; k < info.opened_dex_files.size(); k++) { + std::unique_ptr<const DexFile>& dex = info.opened_dex_files[k]; + info.classpath.push_back(dex->GetLocation()); + info.checksums.push_back(dex->GetLocationChecksum()); + } } return dex_files_open_result_; @@ -637,13 +658,20 @@ static bool IsAbsoluteLocation(const std::string& location) { } bool ClassLoaderContext::VerifyClassLoaderContextMatch(const std::string& context_spec) const { + DCHECK(dex_files_open_attempted_); + DCHECK(dex_files_open_result_); + ClassLoaderContext expected_context; if (!expected_context.Parse(context_spec, /*parse_checksums*/ true)) { LOG(WARNING) << "Invalid class loader context: " << context_spec; return false; } - if (expected_context.special_shared_library_) { + // Special shared library contexts always match. They essentially instruct the runtime + // to ignore the class path check because the oat file is known to be loaded in different + // contexts. OatFileManager will further verify if the oat file can be loaded based on the + // collision check. + if (special_shared_library_ || expected_context.special_shared_library_) { return true; } diff --git a/runtime/class_loader_context.h b/runtime/class_loader_context.h index 9afa880da4..692a6cda5b 100644 --- a/runtime/class_loader_context.h +++ b/runtime/class_loader_context.h @@ -41,7 +41,12 @@ class ClassLoaderContext { // to ClassLoaderInfo::opened_oat_files. The 'classpath_dir' argument specifies the directory to // use for the relative class paths. // Returns true if all dex files where successfully opened. - // It may be called only once per ClassLoaderContext. The second call will abort. + // It may be called only once per ClassLoaderContext. Subsequent calls will return the same + // result without doing anything. + // + // This will replace the class path locations with the locations of the opened dex files. + // (Note that one dex file can contain multidexes. Each multidex will be added to the classpath + // separately.) // // Note that a "false" return could mean that either an apk/jar contained no dex files or // that we hit a I/O or checksum mismatch error. @@ -98,6 +103,7 @@ class ClassLoaderContext { // - the number and type of the class loaders from the chain matches // - the class loader from the same position have the same classpath // (the order and checksum of the dex files matches) + // This should be called after OpenDexFiles(). bool VerifyClassLoaderContextMatch(const std::string& context_spec) const; // Creates the class loader context from the given string. diff --git a/runtime/class_loader_context_test.cc b/runtime/class_loader_context_test.cc index bb4e2739d9..ca6900f3ec 100644 --- a/runtime/class_loader_context_test.cc +++ b/runtime/class_loader_context_test.cc @@ -74,39 +74,29 @@ class ClassLoaderContextTest : public CommonRuntimeTest { void VerifyOpenDexFiles( ClassLoaderContext* context, size_t index, - std::vector<std::vector<std::unique_ptr<const DexFile>>*>& all_dex_files) { + std::vector<std::unique_ptr<const DexFile>>* all_dex_files) { ASSERT_TRUE(context != nullptr); ASSERT_TRUE(context->dex_files_open_attempted_); ASSERT_TRUE(context->dex_files_open_result_); ClassLoaderContext::ClassLoaderInfo& info = context->class_loader_chain_[index]; - ASSERT_EQ(all_dex_files.size(), info.classpath.size()); + ASSERT_EQ(all_dex_files->size(), info.classpath.size()); + ASSERT_EQ(all_dex_files->size(), info.opened_dex_files.size()); size_t cur_open_dex_index = 0; - for (size_t k = 0; k < all_dex_files.size(); k++) { - std::vector<std::unique_ptr<const DexFile>>& dex_files_for_cp_elem = *(all_dex_files[k]); - for (size_t i = 0; i < dex_files_for_cp_elem.size(); i++) { - ASSERT_LT(cur_open_dex_index, info.opened_dex_files.size()); - - std::unique_ptr<const DexFile>& opened_dex_file = + for (size_t k = 0; k < all_dex_files->size(); k++) { + std::unique_ptr<const DexFile>& opened_dex_file = info.opened_dex_files[cur_open_dex_index++]; - std::unique_ptr<const DexFile>& expected_dex_file = dex_files_for_cp_elem[i]; - - std::string expected_location = expected_dex_file->GetBaseLocation(); - UniqueCPtr<const char[]> expected_real_location( - realpath(expected_location.c_str(), nullptr)); - ASSERT_TRUE(expected_real_location != nullptr) << expected_location; - expected_location.assign(expected_real_location.get()); - expected_location += DexFile::GetMultiDexSuffix(expected_dex_file->GetLocation()); - - ASSERT_EQ(expected_location, opened_dex_file->GetLocation()); - ASSERT_EQ(expected_dex_file->GetLocationChecksum(), opened_dex_file->GetLocationChecksum()); - - std::string class_path_location = info.classpath[k]; - UniqueCPtr<const char[]> class_path_location_real( - realpath(class_path_location.c_str(), nullptr)); - ASSERT_TRUE(class_path_location_real != nullptr); - class_path_location.assign(class_path_location_real.get()); - ASSERT_EQ(class_path_location, opened_dex_file->GetBaseLocation()); - } + std::unique_ptr<const DexFile>& expected_dex_file = (*all_dex_files)[k]; + + std::string expected_location = expected_dex_file->GetBaseLocation(); + UniqueCPtr<const char[]> expected_real_location( + realpath(expected_location.c_str(), nullptr)); + ASSERT_TRUE(expected_real_location != nullptr) << expected_location; + expected_location.assign(expected_real_location.get()); + expected_location += DexFile::GetMultiDexSuffix(expected_dex_file->GetLocation()); + + ASSERT_EQ(expected_location, opened_dex_file->GetLocation()); + ASSERT_EQ(expected_dex_file->GetLocationChecksum(), opened_dex_file->GetLocationChecksum()); + ASSERT_EQ(info.classpath[k], opened_dex_file->GetLocation()); } } @@ -148,6 +138,11 @@ class ClassLoaderContextTest : public CommonRuntimeTest { } } + void PretendContextOpenedDexFiles(ClassLoaderContext* context) { + context->dex_files_open_attempted_ = true; + context->dex_files_open_result_ = true; + } + private: void VerifyClassLoaderInfo(ClassLoaderContext* context, size_t index, @@ -167,11 +162,9 @@ class ClassLoaderContextTest : public CommonRuntimeTest { ClassLoaderContext::ClassLoaderType type, const std::string& test_name) { std::vector<std::unique_ptr<const DexFile>> dex_files = OpenTestDexFiles(test_name.c_str()); - std::vector<std::vector<std::unique_ptr<const DexFile>>*> all_dex_files; - all_dex_files.push_back(&dex_files); VerifyClassLoaderInfo(context, index, type, GetTestDexFileName(test_name.c_str())); - VerifyOpenDexFiles(context, index, all_dex_files); + VerifyOpenDexFiles(context, index, &dex_files); } }; @@ -242,11 +235,8 @@ TEST_F(ClassLoaderContextTest, OpenInvalidDexFiles) { TEST_F(ClassLoaderContextTest, OpenValidDexFiles) { std::string multidex_name = GetTestDexFileName("MultiDex"); - std::vector<std::unique_ptr<const DexFile>> multidex_files = OpenTestDexFiles("MultiDex"); std::string myclass_dex_name = GetTestDexFileName("MyClass"); - std::vector<std::unique_ptr<const DexFile>> myclass_dex_files = OpenTestDexFiles("MyClass"); std::string dex_name = GetTestDexFileName("Main"); - std::vector<std::unique_ptr<const DexFile>> dex_files = OpenTestDexFiles("Main"); std::unique_ptr<ClassLoaderContext> context = ClassLoaderContext::Create( @@ -256,14 +246,16 @@ TEST_F(ClassLoaderContextTest, OpenValidDexFiles) { ASSERT_TRUE(context->OpenDexFiles(InstructionSet::kArm, /*classpath_dir*/ "")); VerifyContextSize(context.get(), 2); - std::vector<std::vector<std::unique_ptr<const DexFile>>*> all_dex_files0; - all_dex_files0.push_back(&multidex_files); - all_dex_files0.push_back(&myclass_dex_files); - std::vector<std::vector<std::unique_ptr<const DexFile>>*> all_dex_files1; - all_dex_files1.push_back(&dex_files); - - VerifyOpenDexFiles(context.get(), 0, all_dex_files0); - VerifyOpenDexFiles(context.get(), 1, all_dex_files1); + + std::vector<std::unique_ptr<const DexFile>> all_dex_files0 = OpenTestDexFiles("MultiDex"); + std::vector<std::unique_ptr<const DexFile>> myclass_dex_files = OpenTestDexFiles("MyClass"); + for (size_t i = 0; i < myclass_dex_files.size(); i++) { + all_dex_files0.emplace_back(myclass_dex_files[i].release()); + } + VerifyOpenDexFiles(context.get(), 0, &all_dex_files0); + + std::vector<std::unique_ptr<const DexFile>> all_dex_files1 = OpenTestDexFiles("Main"); + VerifyOpenDexFiles(context.get(), 1, &all_dex_files1); } class ScratchSymLink { @@ -296,11 +288,10 @@ TEST_F(ClassLoaderContextTest, OpenValidDexFilesSymLink) { ASSERT_TRUE(context->OpenDexFiles(InstructionSet::kArm, /*classpath_dir*/ "")); VerifyContextSize(context.get(), 1); - std::vector<std::vector<std::unique_ptr<const DexFile>>*> all_dex_files0; + std::vector<std::unique_ptr<const DexFile>> myclass_dex_files = OpenTestDexFiles("MyClass"); - all_dex_files0.push_back(&myclass_dex_files); - VerifyOpenDexFiles(context.get(), 0, all_dex_files0); + VerifyOpenDexFiles(context.get(), 0, &myclass_dex_files); } TEST_F(ClassLoaderContextTest, OpenInvalidDexFilesMix) { @@ -552,6 +543,9 @@ TEST_F(ClassLoaderContextTest, CreateContextForClassLoader) { TEST_F(ClassLoaderContextTest, VerifyClassLoaderContextMatch) { std::string context_spec = "PCL[a.dex*123:b.dex*456];DLC[c.dex*890]"; std::unique_ptr<ClassLoaderContext> context = ParseContextWithChecksums(context_spec); + // Pretend that we successfully open the dex files to pass the DCHECKS. + // (as it's much easier to test all the corner cases without relying on actual dex files). + PretendContextOpenedDexFiles(context.get()); VerifyContextSize(context.get(), 2); VerifyClassLoaderPCL(context.get(), 0, "a.dex:b.dex"); diff --git a/runtime/native/dalvik_system_DexFile.cc b/runtime/native/dalvik_system_DexFile.cc index 07dfb65972..d40e6d94c9 100644 --- a/runtime/native/dalvik_system_DexFile.cc +++ b/runtime/native/dalvik_system_DexFile.cc @@ -493,6 +493,8 @@ static jint GetDexOptNeeded(JNIEnv* env, if (oat_file_assistant.IsInBootClassPath()) { return OatFileAssistant::kNoDexOptNeeded; } + + // TODO(calin): Extend DexFile.getDexOptNeeded to accept the class loader context. b/62269291. return oat_file_assistant.GetDexOptNeeded(filter, profile_changed, downgrade); } diff --git a/runtime/oat_file.cc b/runtime/oat_file.cc index 86882051bf..e7cbf789c5 100644 --- a/runtime/oat_file.cc +++ b/runtime/oat_file.cc @@ -1619,6 +1619,10 @@ CompilerFilter::Filter OatFile::GetCompilerFilter() const { return GetOatHeader().GetCompilerFilter(); } +std::string OatFile::GetClassLoaderContext() const { + return GetOatHeader().GetStoreValueByKey(OatHeader::kClassPathKey); +}; + OatFile::OatClass OatFile::FindOatClass(const DexFile& dex_file, uint16_t class_def_idx, bool* found) { diff --git a/runtime/oat_file.h b/runtime/oat_file.h index 9a7fe51e8e..0a05b29258 100644 --- a/runtime/oat_file.h +++ b/runtime/oat_file.h @@ -115,6 +115,8 @@ class OatFile { CompilerFilter::Filter GetCompilerFilter() const; + std::string GetClassLoaderContext() const; + const std::string& GetLocation() const { return location_; } diff --git a/runtime/oat_file_assistant.cc b/runtime/oat_file_assistant.cc index 5814df903e..10be5d97d4 100644 --- a/runtime/oat_file_assistant.cc +++ b/runtime/oat_file_assistant.cc @@ -190,9 +190,13 @@ bool OatFileAssistant::Lock(std::string* error_msg) { int OatFileAssistant::GetDexOptNeeded(CompilerFilter::Filter target, bool profile_changed, - bool downgrade) { + bool downgrade, + ClassLoaderContext* class_loader_context) { OatFileInfo& info = GetBestInfo(); - DexOptNeeded dexopt_needed = info.GetDexOptNeeded(target, profile_changed, downgrade); + DexOptNeeded dexopt_needed = info.GetDexOptNeeded(target, + profile_changed, + downgrade, + class_loader_context); if (info.IsOatLocation() || dexopt_needed == kDex2OatFromScratch) { return dexopt_needed; } @@ -227,7 +231,7 @@ bool OatFileAssistant::IsUpToDate() { OatFileAssistant::ResultOfAttemptToUpdate OatFileAssistant::MakeUpToDate(bool profile_changed, - const std::string& class_loader_context, + ClassLoaderContext* class_loader_context, std::string* error_msg) { CompilerFilter::Filter target; if (!GetRuntimeCompilerFilterOption(&target, error_msg)) { @@ -245,7 +249,8 @@ OatFileAssistant::MakeUpToDate(bool profile_changed, // - however, MakeUpToDate will not always succeed (e.g. for primary apks, or for dex files // loaded in other processes). So it boils down to how far do we want to complicate // the logic in order to enable the use of oat files. Maybe its time to try simplify it. - switch (info.GetDexOptNeeded(target, profile_changed, /*downgrade*/ false)) { + switch (info.GetDexOptNeeded( + target, profile_changed, /*downgrade*/ false, class_loader_context)) { case kNoDexOptNeeded: return kUpdateSucceeded; @@ -643,7 +648,7 @@ static bool PrepareOdexDirectories(const std::string& dex_location, OatFileAssistant::ResultOfAttemptToUpdate OatFileAssistant::GenerateOatFileNoChecks( OatFileAssistant::OatFileInfo& info, CompilerFilter::Filter filter, - const std::string& class_loader_context, + const ClassLoaderContext* class_loader_context, std::string* error_msg) { CHECK(error_msg != nullptr); @@ -720,7 +725,10 @@ OatFileAssistant::ResultOfAttemptToUpdate OatFileAssistant::GenerateOatFileNoChe args.push_back("--oat-fd=" + std::to_string(oat_file->Fd())); args.push_back("--oat-location=" + oat_file_name); args.push_back("--compiler-filter=" + CompilerFilter::NameOfFilter(filter)); - args.push_back("--class-loader-context=" + class_loader_context); + const std::string dex2oat_context = class_loader_context == nullptr + ? OatFile::kSpecialSharedLibrary + : class_loader_context->EncodeContextForDex2oat(/*base_dir*/ ""); + args.push_back("--class-loader-context=" + dex2oat_context); if (!Dex2Oat(args, error_msg)) { // Manually delete the oat and vdex files. This ensures there is no garbage @@ -1016,31 +1024,40 @@ OatFileAssistant::OatStatus OatFileAssistant::OatFileInfo::Status() { } OatFileAssistant::DexOptNeeded OatFileAssistant::OatFileInfo::GetDexOptNeeded( - CompilerFilter::Filter target, bool profile_changed, bool downgrade) { + CompilerFilter::Filter target, + bool profile_changed, + bool downgrade, + ClassLoaderContext* context) { + bool compilation_desired = CompilerFilter::IsAotCompilationEnabled(target); bool filter_okay = CompilerFilterIsOkay(target, profile_changed, downgrade); + bool class_loader_context_okay = ClassLoaderContextIsOkay(context); + + // 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 (filter_okay && Status() == kOatUpToDate) { - // The oat file is in good shape as is. - return kNoDexOptNeeded; - } - - if (filter_okay && !compilation_desired && Status() == kOatRelocationOutOfDate) { - // If no compilation is desired, then it doesn't matter if the oat - // file needs relocation. It's in good shape as is. - return kNoDexOptNeeded; - } + if (filter_okay && !compilation_desired && Status() == kOatRelocationOutOfDate) { + // If no compilation is desired, then it doesn't matter if the oat + // file needs relocation. It's in good shape as is. + return kNoDexOptNeeded; + } - if (filter_okay && Status() == kOatRelocationOutOfDate) { - return kDex2OatForRelocation; - } + if (filter_okay && Status() == kOatRelocationOutOfDate) { + return kDex2OatForRelocation; + } - if (IsUseable()) { - return kDex2OatForFilter; - } + if (IsUseable()) { + return kDex2OatForFilter; + } - if (Status() == kOatBootImageOutOfDate) { - return kDex2OatForBootImage; + if (Status() == kOatBootImageOutOfDate) { + return kDex2OatForBootImage; + } } if (oat_file_assistant_->HasOriginalDexFiles()) { @@ -1090,6 +1107,36 @@ bool OatFileAssistant::OatFileInfo::CompilerFilterIsOkay( CompilerFilter::IsAsGoodAs(current, target); } +bool OatFileAssistant::OatFileInfo::ClassLoaderContextIsOkay(ClassLoaderContext* context) { + if (context == nullptr) { + VLOG(oat) << "ClassLoaderContext check ignored: null context"; + return true; + } + + const OatFile* file = GetFile(); + if (file == nullptr) { + return false; + } + + size_t dir_index = file->GetLocation().rfind('/'); + std::string classpath_dir = (dir_index != std::string::npos) + ? file->GetLocation().substr(0, dir_index) + : ""; + + if (!context->OpenDexFiles(oat_file_assistant_->isa_, classpath_dir)) { + VLOG(oat) << "ClassLoaderContext check failed: dex files from the context could not be opened"; + return false; + } + + bool result = context->VerifyClassLoaderContextMatch(file->GetClassLoaderContext()); + 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() { const OatFile* file = GetFile(); return (file != nullptr && file->IsExecutable()); diff --git a/runtime/oat_file_assistant.h b/runtime/oat_file_assistant.h index 5eec943689..6dc3c197b2 100644 --- a/runtime/oat_file_assistant.h +++ b/runtime/oat_file_assistant.h @@ -26,6 +26,7 @@ #include "base/scoped_flock.h" #include "base/unix_file/fd_file.h" #include "compiler_filter.h" +#include "class_loader_context.h" #include "oat_file.h" #include "os.h" @@ -164,7 +165,8 @@ class OatFileAssistant { // the oat file in the odex location. int GetDexOptNeeded(CompilerFilter::Filter target_compiler_filter, bool profile_changed = false, - bool downgrade = false); + bool downgrade = false, + ClassLoaderContext* context = nullptr); // Returns true if there is up-to-date code for this dex location, // irrespective of the compiler filter of the up-to-date code. @@ -194,7 +196,7 @@ class OatFileAssistant { // to a string describing why there was a failure or the update was not // attempted. error_msg must not be null. ResultOfAttemptToUpdate MakeUpToDate(bool profile_changed, - const std::string& class_loader_context, + ClassLoaderContext* class_loader_context, std::string* error_msg); // Returns an oat file that can be used for loading dex files. @@ -330,7 +332,8 @@ class OatFileAssistant { // compiler filter. DexOptNeeded GetDexOptNeeded(CompilerFilter::Filter target_compiler_filter, bool profile_changed, - bool downgrade); + bool downgrade, + ClassLoaderContext* context); // Returns the loaded file. // Loads the file if needed. Returns null if the file failed to load. @@ -367,6 +370,8 @@ class OatFileAssistant { // compiler filter. bool CompilerFilterIsOkay(CompilerFilter::Filter target, bool profile_changed, bool downgrade); + bool ClassLoaderContextIsOkay(ClassLoaderContext* context); + // Release the loaded oat file. // Returns null if the oat file hasn't been loaded. // @@ -404,7 +409,7 @@ class OatFileAssistant { // attempted. error_msg must not be null. ResultOfAttemptToUpdate GenerateOatFileNoChecks(OatFileInfo& info, CompilerFilter::Filter target, - const std::string& class_loader_context, + const ClassLoaderContext* class_loader_context, std::string* error_msg); // Return info for the best oat file. diff --git a/runtime/oat_file_assistant_test.cc b/runtime/oat_file_assistant_test.cc index ea665d9ef7..0ad26d6c66 100644 --- a/runtime/oat_file_assistant_test.cc +++ b/runtime/oat_file_assistant_test.cc @@ -36,6 +36,7 @@ namespace art { static const std::string kSpecialSharedLibrary = "&"; +static ClassLoaderContext* kSpecialSharedLibraryContext = nullptr; class OatFileAssistantTest : public DexoptTest {}; @@ -117,7 +118,7 @@ TEST_F(OatFileAssistantTest, NoDexNoOat) { // Trying to make the oat file up to date should not fail or crash. std::string error_msg; EXPECT_EQ(OatFileAssistant::kUpdateSucceeded, - oat_file_assistant.MakeUpToDate(false, kSpecialSharedLibrary, &error_msg)); + oat_file_assistant.MakeUpToDate(false, kSpecialSharedLibraryContext, &error_msg)); // Trying to get the best oat file should fail, but not crash. std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile(); @@ -770,7 +771,7 @@ TEST_F(OatFileAssistantTest, ResourceOnlyDex) { std::string error_msg; Runtime::Current()->AddCompilerOption("--compiler-filter=speed"); EXPECT_EQ(OatFileAssistant::kUpdateSucceeded, - oat_file_assistant.MakeUpToDate(false, kSpecialSharedLibrary, &error_msg)) << + oat_file_assistant.MakeUpToDate(false, kSpecialSharedLibraryContext, &error_msg)) << error_msg; EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded, @@ -951,7 +952,7 @@ TEST_F(OatFileAssistantTest, GenNoDex) { // We should get kUpdateSucceeded from MakeUpToDate since there's nothing // that can be done in this situation. ASSERT_EQ(OatFileAssistant::kUpdateSucceeded, - oat_file_assistant.MakeUpToDate(false, kSpecialSharedLibrary, &error_msg)); + oat_file_assistant.MakeUpToDate(false, kSpecialSharedLibraryContext, &error_msg)); // Verify it didn't create an oat in the default location (dalvik-cache). OatFileAssistant ofm(dex_location.c_str(), kRuntimeISA, false); @@ -1030,7 +1031,7 @@ TEST_F(OatFileAssistantTest, ShortDexLocation) { std::string error_msg; Runtime::Current()->AddCompilerOption("--compiler-filter=speed"); EXPECT_EQ(OatFileAssistant::kUpdateSucceeded, - oat_file_assistant.MakeUpToDate(false, kSpecialSharedLibrary, &error_msg)); + oat_file_assistant.MakeUpToDate(false, kSpecialSharedLibraryContext, &error_msg)); EXPECT_TRUE(error_msg.empty()); } @@ -1177,7 +1178,7 @@ TEST_F(OatFileAssistantTest, RuntimeCompilerFilterOptionUsed) { std::string error_msg; Runtime::Current()->AddCompilerOption("--compiler-filter=quicken"); EXPECT_EQ(OatFileAssistant::kUpdateSucceeded, - oat_file_assistant.MakeUpToDate(false, kSpecialSharedLibrary, &error_msg)) << + oat_file_assistant.MakeUpToDate(false, kSpecialSharedLibraryContext, &error_msg)) << error_msg; EXPECT_EQ(-OatFileAssistant::kNoDexOptNeeded, oat_file_assistant.GetDexOptNeeded(CompilerFilter::kQuicken)); @@ -1186,7 +1187,7 @@ TEST_F(OatFileAssistantTest, RuntimeCompilerFilterOptionUsed) { Runtime::Current()->AddCompilerOption("--compiler-filter=speed"); EXPECT_EQ(OatFileAssistant::kUpdateSucceeded, - oat_file_assistant.MakeUpToDate(false, kSpecialSharedLibrary, &error_msg)) + oat_file_assistant.MakeUpToDate(false, kSpecialSharedLibraryContext, &error_msg)) << error_msg; EXPECT_EQ(OatFileAssistant::kNoDexOptNeeded, oat_file_assistant.GetDexOptNeeded(CompilerFilter::kQuicken)); @@ -1195,7 +1196,7 @@ TEST_F(OatFileAssistantTest, RuntimeCompilerFilterOptionUsed) { Runtime::Current()->AddCompilerOption("--compiler-filter=bogus"); EXPECT_EQ(OatFileAssistant::kUpdateNotAttempted, - oat_file_assistant.MakeUpToDate(false, kSpecialSharedLibrary, &error_msg)); + oat_file_assistant.MakeUpToDate(false, kSpecialSharedLibraryContext, &error_msg)); } TEST(OatFileAssistantUtilsTest, DexLocationToOdexFilename) { @@ -1255,7 +1256,7 @@ TEST_F(OatFileAssistantTest, DefaultMakeUpToDateFilter) { OatFileAssistant::kDefaultCompilerFilterForDexLoading; std::string error_msg; EXPECT_EQ(OatFileAssistant::kUpdateSucceeded, - oat_file_assistant.MakeUpToDate(false, kSpecialSharedLibrary, &error_msg)) << + oat_file_assistant.MakeUpToDate(false, kSpecialSharedLibraryContext, &error_msg)) << error_msg; EXPECT_EQ(-OatFileAssistant::kNoDexOptNeeded, oat_file_assistant.GetDexOptNeeded(default_filter)); @@ -1273,7 +1274,7 @@ TEST_F(OatFileAssistantTest, MakeUpToDateWithSpecialSharedLibrary) { const CompilerFilter::Filter default_filter = OatFileAssistant::kDefaultCompilerFilterForDexLoading; std::string error_msg; - int status = oat_file_assistant.MakeUpToDate(false, kSpecialSharedLibrary, &error_msg); + int status = oat_file_assistant.MakeUpToDate(false, kSpecialSharedLibraryContext, &error_msg); EXPECT_EQ(OatFileAssistant::kUpdateSucceeded, status) << error_msg; EXPECT_EQ(-OatFileAssistant::kNoDexOptNeeded, oat_file_assistant.GetDexOptNeeded(default_filter)); @@ -1295,19 +1296,52 @@ TEST_F(OatFileAssistantTest, MakeUpToDateWithContext) { OatFileAssistant::kDefaultCompilerFilterForDexLoading; std::string error_msg; std::string context_str = "PCL[" + context_location + "]"; - int status = oat_file_assistant.MakeUpToDate(false, context_str, &error_msg); + std::unique_ptr<ClassLoaderContext> context = ClassLoaderContext::Create(context_str); + ASSERT_TRUE(context != nullptr); + ASSERT_TRUE(context->OpenDexFiles(kRuntimeISA, "")); + + int status = oat_file_assistant.MakeUpToDate(false, context.get(), &error_msg); EXPECT_EQ(OatFileAssistant::kUpdateSucceeded, status) << error_msg; EXPECT_EQ(-OatFileAssistant::kNoDexOptNeeded, - oat_file_assistant.GetDexOptNeeded(default_filter)); + oat_file_assistant.GetDexOptNeeded(default_filter, false, false, context.get())); + std::unique_ptr<OatFile> oat_file = oat_file_assistant.GetBestOatFile(); EXPECT_NE(nullptr, oat_file.get()); - std::unique_ptr<ClassLoaderContext> context = - ClassLoaderContext::Create(context_str); - context->OpenDexFiles(kRuntimeISA, ""); EXPECT_EQ(context->EncodeContextForOatFile(""), oat_file->GetOatHeader().GetStoreValueByKey(OatHeader::kClassPathKey)); } +TEST_F(OatFileAssistantTest, GetDexOptNeededWithOutOfDateContext) { + std::string dex_location = GetScratchDir() + "/TestDex.jar"; + std::string context_location = GetScratchDir() + "/ContextDex.jar"; + Copy(GetDexSrc1(), dex_location); + Copy(GetDexSrc2(), context_location); + + OatFileAssistant oat_file_assistant(dex_location.c_str(), kRuntimeISA, false); + + const CompilerFilter::Filter default_filter = + OatFileAssistant::kDefaultCompilerFilterForDexLoading; + std::string error_msg; + std::string context_str = "PCL[" + context_location + "]"; + std::unique_ptr<ClassLoaderContext> context = ClassLoaderContext::Create(context_str); + ASSERT_TRUE(context != nullptr); + ASSERT_TRUE(context->OpenDexFiles(kRuntimeISA, "")); + + int status = oat_file_assistant.MakeUpToDate(false, context.get(), &error_msg); + EXPECT_EQ(OatFileAssistant::kUpdateSucceeded, status) << error_msg; + EXPECT_EQ(-OatFileAssistant::kNoDexOptNeeded, + oat_file_assistant.GetDexOptNeeded(default_filter, false, false, context.get())); + + // Update the context by overriding the jar file. + Copy(GetMultiDexSrc2(), context_location); + std::unique_ptr<ClassLoaderContext> updated_context = ClassLoaderContext::Create(context_str); + ASSERT_TRUE(updated_context != nullptr); + // DexOptNeeded should advise compilation from scratch. + EXPECT_EQ(OatFileAssistant::kDex2OatFromScratch, + oat_file_assistant.GetDexOptNeeded( + default_filter, false, false, updated_context.get())); +} + // TODO: More Tests: // * Test class linker falls back to unquickened dex for DexNoOat // * Test class linker falls back to unquickened dex for MultiDexNoOat diff --git a/runtime/oat_file_manager.cc b/runtime/oat_file_manager.cc index 499f356a3a..516c833c6d 100644 --- a/runtime/oat_file_manager.cc +++ b/runtime/oat_file_manager.cc @@ -361,8 +361,7 @@ bool OatFileManager::HasCollisions(const OatFile* oat_file, // If the pat file loading context matches the context used during compilation then we accept // the oat file without addition checks - if (context->VerifyClassLoaderContextMatch( - oat_file->GetOatHeader().GetStoreValueByKey(OatHeader::kClassPathKey))) { + if (context->VerifyClassLoaderContextMatch(oat_file->GetClassLoaderContext())) { return false; } @@ -426,12 +425,9 @@ std::vector<std::unique_ptr<const DexFile>> OatFileManager::OpenDexFilesFromOat( // Update the oat file on disk if we can, based on the --compiler-filter // option derived from the current runtime options. // This may fail, but that's okay. Best effort is all that matters here. - - const std::string& dex2oat_context = context == nullptr - ? OatFile::kSpecialSharedLibrary - : context->EncodeContextForDex2oat(/*base_dir*/ ""); - switch (oat_file_assistant.MakeUpToDate( - /*profile_changed*/false, dex2oat_context, /*out*/ &error_msg)) { + switch (oat_file_assistant.MakeUpToDate(/*profile_changed*/false, + context.get(), + /*out*/ &error_msg)) { case OatFileAssistant::kUpdateFailed: LOG(WARNING) << error_msg; break; |