summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--runtime/class_loader_context.cc32
-rw-r--r--runtime/class_loader_context.h8
-rw-r--r--runtime/class_loader_context_test.cc147
3 files changed, 93 insertions, 94 deletions
diff --git a/runtime/class_loader_context.cc b/runtime/class_loader_context.cc
index 56573f550e..3bd45966e4 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 18472743fb..ae3dcecb4a 100644
--- a/runtime/class_loader_context_test.cc
+++ b/runtime/class_loader_context_test.cc
@@ -87,60 +87,29 @@ class ClassLoaderContextTest : public CommonRuntimeTest {
void VerifyOpenDexFiles(
ClassLoaderContext* context,
size_t index,
- std::vector<std::vector<std::unique_ptr<const DexFile>>*>& all_dex_files,
- LocationCheck mode = LocationCheck::kEquals,
- BaseLocationCheck base_mode = BaseLocationCheck::kEquals) {
+ 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());
-
- switch (mode) {
- case LocationCheck::kEquals:
- ASSERT_EQ(expected_dex_file->GetLocation(), opened_dex_file->GetLocation());
- break;
- case LocationCheck::kEndsWith:
- ASSERT_TRUE(android::base::EndsWith(expected_dex_file->GetLocation(),
- opened_dex_file->GetLocation().c_str()))
- << opened_dex_file->GetLocation() << " vs " << expected_dex_file->GetLocation();
- break;
- }
- 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());
- switch (base_mode) {
- case BaseLocationCheck::kEquals:
- ASSERT_EQ(class_path_location, opened_dex_file->GetBaseLocation());
- break;
-
- case BaseLocationCheck::kEndsWith:
- ASSERT_TRUE(android::base::EndsWith(opened_dex_file->GetBaseLocation(),
- class_path_location.c_str()))
- << info.classpath[k] << " vs " << opened_dex_file->GetBaseLocation();
- break;
- }
- }
+ 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());
}
}
@@ -182,6 +151,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,
@@ -201,11 +175,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);
}
};
@@ -276,11 +248,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(
@@ -290,14 +259,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 {
@@ -330,11 +301,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);
}
static std::string CreateRelativeString(const std::string& in, const char* cwd) {
@@ -353,11 +323,8 @@ TEST_F(ClassLoaderContextTest, OpenValidDexFilesRelative) {
PLOG(FATAL) << "Could not get working directory";
}
std::string multidex_name = CreateRelativeString(GetTestDexFileName("MultiDex"), cwd_buf);
- std::vector<std::unique_ptr<const DexFile>> multidex_files = OpenTestDexFiles("MultiDex");
std::string myclass_dex_name = CreateRelativeString(GetTestDexFileName("MyClass"), cwd_buf);
- std::vector<std::unique_ptr<const DexFile>> myclass_dex_files = OpenTestDexFiles("MyClass");
std::string dex_name = CreateRelativeString(GetTestDexFileName("Main"), cwd_buf);
- std::vector<std::unique_ptr<const DexFile>> dex_files = OpenTestDexFiles("Main");
std::unique_ptr<ClassLoaderContext> context =
@@ -367,15 +334,15 @@ TEST_F(ClassLoaderContextTest, OpenValidDexFilesRelative) {
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, LocationCheck::kEndsWith);
- VerifyOpenDexFiles(context.get(), 1, all_dex_files1, LocationCheck::kEndsWith);
+ 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);
}
TEST_F(ClassLoaderContextTest, OpenValidDexFilesClasspathDir) {
@@ -384,12 +351,8 @@ TEST_F(ClassLoaderContextTest, OpenValidDexFilesClasspathDir) {
PLOG(FATAL) << "Could not get working directory";
}
std::string multidex_name = CreateRelativeString(GetTestDexFileName("MultiDex"), cwd_buf);
- std::vector<std::unique_ptr<const DexFile>> multidex_files = OpenTestDexFiles("MultiDex");
std::string myclass_dex_name = CreateRelativeString(GetTestDexFileName("MyClass"), cwd_buf);
- std::vector<std::unique_ptr<const DexFile>> myclass_dex_files = OpenTestDexFiles("MyClass");
std::string dex_name = CreateRelativeString(GetTestDexFileName("Main"), cwd_buf);
- std::vector<std::unique_ptr<const DexFile>> dex_files = OpenTestDexFiles("Main");
-
std::unique_ptr<ClassLoaderContext> context =
ClassLoaderContext::Create(
@@ -399,16 +362,15 @@ TEST_F(ClassLoaderContextTest, OpenValidDexFilesClasspathDir) {
ASSERT_TRUE(context->OpenDexFiles(InstructionSet::kArm, cwd_buf));
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, LocationCheck::kEquals, BaseLocationCheck::kEndsWith);
- VerifyOpenDexFiles(
- context.get(), 1, all_dex_files1, LocationCheck::kEquals, BaseLocationCheck::kEndsWith);
+ 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);
}
TEST_F(ClassLoaderContextTest, OpenInvalidDexFilesMix) {
@@ -660,6 +622,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");