summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorandroid-build-team Robot <android-build-team-robot@google.com>2017-09-17 07:34:57 +0000
committerandroid-build-team Robot <android-build-team-robot@google.com>2017-09-17 07:34:57 +0000
commit171693533c0d80eb7d5d88edb75db691582a54ad (patch)
treea8f719af7bc66652f037e9ab15661afaa2b8e446
parentc831b1889651396ddf27a1ef9a944ecff21f030f (diff)
parentb6471ac0749b58a68954a61c71b4695b6b86449d (diff)
downloadart-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.cc2
-rw-r--r--runtime/class_loader_context.cc32
-rw-r--r--runtime/class_loader_context.h8
-rw-r--r--runtime/class_loader_context_test.cc82
-rw-r--r--runtime/native/dalvik_system_DexFile.cc2
-rw-r--r--runtime/oat_file.cc4
-rw-r--r--runtime/oat_file.h2
-rw-r--r--runtime/oat_file_assistant.cc97
-rw-r--r--runtime/oat_file_assistant.h13
-rw-r--r--runtime/oat_file_assistant_test.cc62
-rw-r--r--runtime/oat_file_manager.cc12
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;