summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--dexoptanalyzer/dexoptanalyzer.cc2
-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
8 files changed, 143 insertions, 51 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/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 6515cfa864..075875b3f4 100644
--- a/runtime/oat_file.cc
+++ b/runtime/oat_file.cc
@@ -1604,6 +1604,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 e13126bae3..04cb3a0a6e 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 3794f51cb7..83a8e096e4 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 e048177fa4..3ecd1b516d 100644
--- a/runtime/oat_file_assistant_test.cc
+++ b/runtime/oat_file_assistant_test.cc
@@ -40,6 +40,7 @@
namespace art {
static const std::string kSpecialSharedLibrary = "&";
+static ClassLoaderContext* kSpecialSharedLibraryContext = nullptr;
class OatFileAssistantTest : public DexoptTest {};
@@ -121,7 +122,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();
@@ -774,7 +775,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,
@@ -955,7 +956,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);
@@ -1034,7 +1035,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());
}
@@ -1181,7 +1182,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));
@@ -1190,7 +1191,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));
@@ -1199,7 +1200,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) {
@@ -1259,7 +1260,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));
@@ -1277,7 +1278,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));
@@ -1299,19 +1300,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;