diff options
Diffstat (limited to 'runtime/class_loader_context_test.cc')
-rw-r--r-- | runtime/class_loader_context_test.cc | 305 |
1 files changed, 193 insertions, 112 deletions
diff --git a/runtime/class_loader_context_test.cc b/runtime/class_loader_context_test.cc index 987f0d14fd..ec51dee06c 100644 --- a/runtime/class_loader_context_test.cc +++ b/runtime/class_loader_context_test.cc @@ -142,22 +142,38 @@ class ClassLoaderContextTest : public CommonRuntimeTest { ClassLoaderContext* context, size_t index, std::vector<std::unique_ptr<const DexFile>>* all_dex_files, - bool classpath_matches_dex_location = true) { + bool classpath_matches_dex_location = true, + bool only_read_checksums = false) { ASSERT_TRUE(context != nullptr); - ASSERT_TRUE(context->dex_files_open_attempted_); - ASSERT_TRUE(context->dex_files_open_result_); + if (only_read_checksums) { + ASSERT_EQ(context->dex_files_state_, + ClassLoaderContext::ContextDexFilesState::kDexFilesChecksumsRead); + } else { + ASSERT_EQ(context->dex_files_state_, + ClassLoaderContext::ContextDexFilesState::kDexFilesOpened); + } ClassLoaderContext::ClassLoaderInfo& info = *context->GetParent(index); 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::unique_ptr<const DexFile>& opened_dex_file = - info.opened_dex_files[cur_open_dex_index++]; - std::unique_ptr<const DexFile>& expected_dex_file = (*all_dex_files)[k]; + ASSERT_EQ(all_dex_files->size(), info.checksums.size()); + if (only_read_checksums) { + ASSERT_EQ(0u, info.opened_dex_files.size()); + } else { + ASSERT_EQ(all_dex_files->size(), info.opened_dex_files.size()); + } + for (size_t k = 0, cur_open_dex_index = 0; + k < all_dex_files->size(); + k++, cur_open_dex_index++) { + const std::string& opened_location = only_read_checksums + ? info.classpath[cur_open_dex_index] + : info.opened_dex_files[cur_open_dex_index]->GetLocation(); + uint32_t opened_checksum = only_read_checksums + ? info.checksums[cur_open_dex_index] + : info.opened_dex_files[cur_open_dex_index]->GetLocationChecksum(); + + std::unique_ptr<const DexFile>& expected_dex_file = (*all_dex_files)[k]; std::string expected_location = expected_dex_file->GetLocation(); - const std::string& opened_location = opened_dex_file->GetLocation(); if (!IsAbsoluteLocation(opened_location)) { // If the opened location is relative (it was open from a relative path without a // classpath_dir) it might not match the expected location which is absolute in tests). @@ -169,7 +185,7 @@ class ClassLoaderContextTest : public CommonRuntimeTest { } else { ASSERT_EQ(expected_location, opened_location); } - ASSERT_EQ(expected_dex_file->GetLocationChecksum(), opened_dex_file->GetLocationChecksum()); + ASSERT_EQ(expected_dex_file->GetLocationChecksum(), opened_checksum); if (classpath_matches_dex_location) { ASSERT_EQ(info.classpath[k], opened_location); } @@ -190,8 +206,7 @@ class ClassLoaderContextTest : public CommonRuntimeTest { void VerifyContextForClassLoader(ClassLoaderContext* context) { ASSERT_TRUE(context != nullptr); - ASSERT_TRUE(context->dex_files_open_attempted_); - ASSERT_TRUE(context->dex_files_open_result_); + ASSERT_EQ(context->dex_files_state_, ClassLoaderContext::ContextDexFilesState::kDexFilesOpened); ASSERT_FALSE(context->owns_the_dex_files_); ASSERT_FALSE(context->special_shared_library_); } @@ -215,8 +230,106 @@ class ClassLoaderContextTest : public CommonRuntimeTest { } void PretendContextOpenedDexFiles(ClassLoaderContext* context) { - context->dex_files_open_attempted_ = true; - context->dex_files_open_result_ = true; + context->dex_files_state_ = ClassLoaderContext::ContextDexFilesState::kDexFilesOpened; + } + + void PretendContextOpenedDexFilesForChecksums(ClassLoaderContext* context) { + context->dex_files_state_ = ClassLoaderContext::ContextDexFilesState::kDexFilesChecksumsRead; + } + + void TestOpenDexFiles(bool only_read_checksums) { + std::string multidex_name = GetTestDexFileName("MultiDex"); + std::string myclass_dex_name = GetTestDexFileName("MyClass"); + std::string dex_name = GetTestDexFileName("Main"); + + std::unique_ptr<ClassLoaderContext> context = + ClassLoaderContext::Create( + "PCL[" + multidex_name + ":" + myclass_dex_name + "];" + + "DLC[" + dex_name + "]"); + + ASSERT_TRUE(context->OpenDexFiles( + /*classpath_dir=*/ "", + /*context_fds=*/ std::vector<int>(), + only_read_checksums)); + + VerifyContextSize(context.get(), 2); + + 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(), + /*index=*/ 0, + &all_dex_files0, + /*classpath_matches_dex_location=*/ false, + only_read_checksums); + std::vector<std::unique_ptr<const DexFile>> all_dex_files1 = OpenTestDexFiles("Main"); + VerifyOpenDexFiles(context.get(), + /*index=*/ 1, + &all_dex_files1, + /*classpath_matches_dex_location=*/ false, + only_read_checksums); + } + + void TestOpenValidDexFilesRelative(bool use_classpath_dir, bool only_read_checksums) { + char cwd_buf[4096]; + if (getcwd(cwd_buf, arraysize(cwd_buf)) == nullptr) { + PLOG(FATAL) << "Could not get working directory"; + } + std::string multidex_name; + std::string myclass_dex_name; + std::string dex_name; + if (!CreateRelativeString(GetTestDexFileName("MultiDex"), cwd_buf, &multidex_name) || + !CreateRelativeString(GetTestDexFileName("MyClass"), cwd_buf, &myclass_dex_name) || + !CreateRelativeString(GetTestDexFileName("Main"), cwd_buf, &dex_name)) { + LOG(ERROR) << "Test OpenValidDexFilesRelative cannot be run because target dex files have no " + << "relative path."; + SUCCEED(); + return; + } + + std::unique_ptr<ClassLoaderContext> context = + ClassLoaderContext::Create( + "PCL[" + multidex_name + ":" + myclass_dex_name + "];" + + "DLC[" + dex_name + "]"); + + ASSERT_TRUE(context->OpenDexFiles( + /*classpath_dir=*/ use_classpath_dir ? cwd_buf : "", + /*context_fds=*/ std::vector<int>(), + only_read_checksums)); + VerifyContextSize(context.get(), 2); + + 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(), + /*index=*/ 0, + &all_dex_files0, + /*classpath_matches_dex_location=*/ false, + only_read_checksums); + + std::vector<std::unique_ptr<const DexFile>> all_dex_files1 = OpenTestDexFiles("Main"); + VerifyOpenDexFiles(context.get(), + /*index=*/ 1, + &all_dex_files1, + /*classpath_matches_dex_location=*/ false, + only_read_checksums); + } + + // Creates a relative path from cwd to 'in'. Returns false if it cannot be done. + // TODO We should somehow support this in all situations. b/72042237. + bool CreateRelativeString(const std::string& in, const char* cwd, std::string* out) { + int cwd_len = strlen(cwd); + if (!android::base::StartsWith(in, cwd) || (cwd_len < 1)) { + return false; + } + bool contains_trailing_slash = (cwd[cwd_len - 1] == '/'); + int start_position = cwd_len + (contains_trailing_slash ? 0 : 1); + *out = in.substr(start_position); + return true; } private: @@ -404,113 +517,38 @@ TEST_F(ClassLoaderContextTest, OpenInvalidDexFiles) { ASSERT_FALSE(context->OpenDexFiles(".")); } -TEST_F(ClassLoaderContextTest, OpenValidDexFiles) { - std::string multidex_name = GetTestDexFileName("MultiDex"); - std::string myclass_dex_name = GetTestDexFileName("MyClass"); - std::string dex_name = GetTestDexFileName("Main"); - - +TEST_F(ClassLoaderContextTest, ReadChecksumsInvalidDexFiles) { std::unique_ptr<ClassLoaderContext> context = - ClassLoaderContext::Create( - "PCL[" + multidex_name + ":" + myclass_dex_name + "];" + - "DLC[" + dex_name + "]"); - - ASSERT_TRUE(context->OpenDexFiles()); - - VerifyContextSize(context.get(), 2); - - 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); + ClassLoaderContext::Create("PCL[does_not_exist.dex]"); + VerifyContextSize(context.get(), 1); + ASSERT_FALSE(context->OpenDexFiles( + /*classpath_dir=*/ ".", + /*context_fds=*/ std::vector<int>(), + /*only_read_checksums=*/ true)); +} - std::vector<std::unique_ptr<const DexFile>> all_dex_files1 = OpenTestDexFiles("Main"); - VerifyOpenDexFiles(context.get(), 1, &all_dex_files1); +TEST_F(ClassLoaderContextTest, OpenValidDexFiles) { + TestOpenDexFiles(/*only_read_checksums=*/ false); } -// Creates a relative path from cwd to 'in'. Returns false if it cannot be done. -// TODO We should somehow support this in all situations. b/72042237. -static bool CreateRelativeString(const std::string& in, const char* cwd, std::string* out) { - int cwd_len = strlen(cwd); - if (!android::base::StartsWith(in, cwd) || (cwd_len < 1)) { - return false; - } - bool contains_trailing_slash = (cwd[cwd_len - 1] == '/'); - int start_position = cwd_len + (contains_trailing_slash ? 0 : 1); - *out = in.substr(start_position); - return true; +TEST_F(ClassLoaderContextTest, ReadDexFileChecksums) { + TestOpenDexFiles(/*only_read_checksums=*/ true); } TEST_F(ClassLoaderContextTest, OpenValidDexFilesRelative) { - char cwd_buf[4096]; - if (getcwd(cwd_buf, arraysize(cwd_buf)) == nullptr) { - PLOG(FATAL) << "Could not get working directory"; - } - std::string multidex_name; - std::string myclass_dex_name; - std::string dex_name; - if (!CreateRelativeString(GetTestDexFileName("MultiDex"), cwd_buf, &multidex_name) || - !CreateRelativeString(GetTestDexFileName("MyClass"), cwd_buf, &myclass_dex_name) || - !CreateRelativeString(GetTestDexFileName("Main"), cwd_buf, &dex_name)) { - LOG(ERROR) << "Test OpenValidDexFilesRelative cannot be run because target dex files have no " - << "relative path."; - SUCCEED(); - return; - } - - std::unique_ptr<ClassLoaderContext> context = - ClassLoaderContext::Create( - "PCL[" + multidex_name + ":" + myclass_dex_name + "];" + - "DLC[" + dex_name + "]"); - - ASSERT_TRUE(context->OpenDexFiles()); - - 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); + TestOpenValidDexFilesRelative(/*use_classpath_dir=*/ false, /*only_read_checksums=*/ false); +} - std::vector<std::unique_ptr<const DexFile>> all_dex_files1 = OpenTestDexFiles("Main"); - VerifyOpenDexFiles(context.get(), 1, &all_dex_files1); +TEST_F(ClassLoaderContextTest, ReadChecksumsValidDexFilesRelative) { + TestOpenValidDexFilesRelative(/*use_classpath_dir=*/ false, /*only_read_checksums=*/ true); } TEST_F(ClassLoaderContextTest, OpenValidDexFilesClasspathDir) { - char cwd_buf[4096]; - if (getcwd(cwd_buf, arraysize(cwd_buf)) == nullptr) { - PLOG(FATAL) << "Could not get working directory"; - } - std::string multidex_name; - std::string myclass_dex_name; - std::string dex_name; - if (!CreateRelativeString(GetTestDexFileName("MultiDex"), cwd_buf, &multidex_name) || - !CreateRelativeString(GetTestDexFileName("MyClass"), cwd_buf, &myclass_dex_name) || - !CreateRelativeString(GetTestDexFileName("Main"), cwd_buf, &dex_name)) { - LOG(ERROR) << "Test OpenValidDexFilesClasspathDir cannot be run because target dex files have " - << "no relative path."; - SUCCEED(); - return; - } - std::unique_ptr<ClassLoaderContext> context = - ClassLoaderContext::Create( - "PCL[" + multidex_name + ":" + myclass_dex_name + "];" + - "DLC[" + dex_name + "]"); - - ASSERT_TRUE(context->OpenDexFiles(cwd_buf)); - - VerifyContextSize(context.get(), 2); - 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); + TestOpenValidDexFilesRelative(/*use_classpath_dir=*/ true, /*only_read_checksums=*/ false); +} - std::vector<std::unique_ptr<const DexFile>> all_dex_files1 = OpenTestDexFiles("Main"); - VerifyOpenDexFiles(context.get(), 1, &all_dex_files1); +TEST_F(ClassLoaderContextTest, ReadChecksumsValidDexFilesClasspathDir) { + TestOpenValidDexFilesRelative(/*use_classpath_dir=*/ true, /*only_read_checksums=*/ true); } TEST_F(ClassLoaderContextTest, OpenInvalidDexFilesMix) { @@ -520,6 +558,16 @@ TEST_F(ClassLoaderContextTest, OpenInvalidDexFilesMix) { ASSERT_FALSE(context->OpenDexFiles()); } +TEST_F(ClassLoaderContextTest, ReadChecksumsInvalidDexFilesMix) { + std::string dex_name = GetTestDexFileName("Main"); + std::unique_ptr<ClassLoaderContext> context = + ClassLoaderContext::Create("PCL[does_not_exist.dex];DLC[" + dex_name + "]"); + ASSERT_FALSE(context->OpenDexFiles( + /*classpath_dir=*/ "", + /*context_fds=*/ std::vector<int>(), + /*only_read_checksums=*/ true)); +} + TEST_F(ClassLoaderContextTest, OpenDexFilesForIMCFails) { std::unique_ptr<ClassLoaderContext> context; std::string dex_name = GetTestDexFileName("Main"); @@ -529,6 +577,39 @@ TEST_F(ClassLoaderContextTest, OpenDexFilesForIMCFails) { ASSERT_FALSE(context->OpenDexFiles(".")); } +// Verify that we can fully open the dex files after only reading their checksums. +TEST_F(ClassLoaderContextTest, SubsequentOpenDexFilesOperations) { + std::string dex_name = GetTestDexFileName("Main"); + std::unique_ptr<ClassLoaderContext> context = + ClassLoaderContext::Create("PCL[" + dex_name + "]"); + + std::vector<std::unique_ptr<const DexFile>> all_dex_files0 = OpenTestDexFiles("Main"); + + ASSERT_TRUE(context->OpenDexFiles( + /*classpath_dir=*/ "", + /*context_fds=*/ std::vector<int>(), + /*only_read_checksums=*/ true)); + + VerifyOpenDexFiles( + context.get(), + /*index=*/ 0, + &all_dex_files0, + /*classpath_matches_dex_location=*/ false, + /*only_read_checksums=*/ true); + + ASSERT_TRUE(context->OpenDexFiles( + /*classpath_dir=*/ "", + /*context_fds=*/ std::vector<int>(), + /*only_read_checksums=*/ false)); + + VerifyOpenDexFiles( + context.get(), + /*index=*/ 0, + &all_dex_files0, + /*classpath_matches_dex_location=*/ false, + /*only_read_checksums=*/ false); +} + TEST_F(ClassLoaderContextTest, CreateClassLoader) { std::string dex_name = GetTestDexFileName("Main"); std::unique_ptr<ClassLoaderContext> context = @@ -1393,7 +1474,7 @@ TEST_F(ClassLoaderContextTest, VerifyClassLoaderContextFirstElement) { std::string context_spec = "PCL[]"; std::unique_ptr<ClassLoaderContext> context = ParseContextWithChecksums(context_spec); ASSERT_TRUE(context != nullptr); - PretendContextOpenedDexFiles(context.get()); + PretendContextOpenedDexFilesForChecksums(context.get()); // Ensure that the special shared library marks as verified for the first thing in the class path. ASSERT_EQ(context->VerifyClassLoaderContextMatch(OatFile::kSpecialSharedLibrary), ClassLoaderContext::VerificationResult::kVerifies); @@ -1404,7 +1485,7 @@ TEST_F(ClassLoaderContextTest, VerifyClassLoaderContextMatch) { 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()); + PretendContextOpenedDexFilesForChecksums(context.get()); VerifyContextSize(context.get(), 2); VerifyClassLoaderPCL(context.get(), 0, "a.dex:b.dex"); |