diff options
author | 2018-11-16 10:25:42 +0000 | |
---|---|---|
committer | 2018-11-19 21:20:58 +0000 | |
commit | 6b9fd8c23a27b11961fcdcf43504c06a654fb83b (patch) | |
tree | e33849628ae15b059087395f0268d95c7dfeea73 | |
parent | b321ac28f726a7ed41f277382d85702ffdfbe00f (diff) |
Support shared libraries in ClassLoaderContext::CreateClassLoader.
bug: 111174995
Test: dex2oat_test, class_loader_context_test
Change-Id: I482012eca408f9e064d7c3d787662376e1b0de3b
-rw-r--r-- | dex2oat/dex2oat_test.cc | 11 | ||||
-rw-r--r-- | runtime/class_linker.cc | 81 | ||||
-rw-r--r-- | runtime/class_linker.h | 10 | ||||
-rw-r--r-- | runtime/class_loader_context.cc | 83 | ||||
-rw-r--r-- | runtime/class_loader_context_test.cc | 288 | ||||
-rw-r--r-- | runtime/class_root.h | 1 |
6 files changed, 427 insertions, 47 deletions
diff --git a/dex2oat/dex2oat_test.cc b/dex2oat/dex2oat_test.cc index baeebd9371..1fa21d51fc 100644 --- a/dex2oat/dex2oat_test.cc +++ b/dex2oat/dex2oat_test.cc @@ -1202,6 +1202,17 @@ TEST_F(Dex2oatClassLoaderContextTest, ChainContext) { RunTest(context.c_str(), expected_classpath_key.c_str(), true); } +TEST_F(Dex2oatClassLoaderContextTest, ContextWithSharedLibrary) { + std::vector<std::unique_ptr<const DexFile>> dex_files1 = OpenTestDexFiles("Nested"); + std::vector<std::unique_ptr<const DexFile>> dex_files2 = OpenTestDexFiles("MultiDex"); + + std::string context = "PCL[" + GetTestDexFileName("Nested") + "]" + + "{PCL[" + GetTestDexFileName("MultiDex") + "]}"; + std::string expected_classpath_key = "PCL[" + CreateClassPathWithChecksums(dex_files1) + "]" + + "{PCL[" + CreateClassPathWithChecksums(dex_files2) + "]}"; + RunTest(context.c_str(), expected_classpath_key.c_str(), true); +} + class Dex2oatDeterminism : public Dex2oatTest {}; TEST_F(Dex2oatDeterminism, UnloadCompile) { diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc index 35379cc251..9e31a20ada 100644 --- a/runtime/class_linker.cc +++ b/runtime/class_linker.cc @@ -798,6 +798,8 @@ bool ClassLinker::InitWithoutImage(std::vector<std::unique_ptr<const DexFile>> b FindSystemClass(self, "Ljava/lang/StackTraceElement;")); SetClassRoot(ClassRoot::kJavaLangStackTraceElementArrayClass, FindSystemClass(self, "[Ljava/lang/StackTraceElement;")); + SetClassRoot(ClassRoot::kJavaLangClassLoaderArrayClass, + FindSystemClass(self, "[Ljava/lang/ClassLoader;")); // Create conflict tables that depend on the class linker. runtime->FixupConflictTables(); @@ -9005,21 +9007,14 @@ void ClassLinker::AllocAndSetPrimitiveArrayClassRoot(Thread* self, CheckSystemClass(self, primitive_array_class, descriptor); } -jobject ClassLinker::CreateWellKnownClassLoader(Thread* self, - const std::vector<const DexFile*>& dex_files, - jclass loader_class, - jobject parent_loader) { - CHECK(self->GetJniEnv()->IsSameObject(loader_class, - WellKnownClasses::dalvik_system_PathClassLoader) || - self->GetJniEnv()->IsSameObject(loader_class, - WellKnownClasses::dalvik_system_DelegateLastClassLoader)); - - // SOAAlreadyRunnable is protected, and we need something to add a global reference. - // We could move the jobject to the callers, but all call-sites do this... - ScopedObjectAccessUnchecked soa(self); +ObjPtr<mirror::ClassLoader> ClassLinker::CreateWellKnownClassLoader( + Thread* self, + const std::vector<const DexFile*>& dex_files, + Handle<mirror::Class> loader_class, + Handle<mirror::ObjectArray<mirror::ClassLoader>> shared_libraries, + Handle<mirror::ClassLoader> parent_loader) { - // For now, create a libcore-level DexFile for each ART DexFile. This "explodes" multidex. - StackHandleScope<6> hs(self); + StackHandleScope<5> hs(self); ArtField* dex_elements_field = jni::DecodeArtField(WellKnownClasses::dalvik_system_DexPathList_dexElements); @@ -9109,8 +9104,8 @@ jobject ClassLinker::CreateWellKnownClassLoader(Thread* self, } // Create the class loader.. - Handle<mirror::Class> h_loader_class = hs.NewHandle(soa.Decode<mirror::Class>(loader_class)); - Handle<mirror::Object> h_class_loader = hs.NewHandle(h_loader_class->AllocObject(self)); + Handle<mirror::ClassLoader> h_class_loader = hs.NewHandle<mirror::ClassLoader>( + ObjPtr<mirror::ClassLoader>::DownCast(loader_class->AllocObject(self))); DCHECK(h_class_loader != nullptr); // Set DexPathList. ArtField* path_list_field = @@ -9126,15 +9121,59 @@ jobject ClassLinker::CreateWellKnownClassLoader(Thread* self, "parent", "Ljava/lang/ClassLoader;"); DCHECK(parent_field != nullptr); + if (parent_loader.Get() == nullptr) { + ScopedObjectAccessUnchecked soa(self); + ObjPtr<mirror::Object> boot_loader(soa.Decode<mirror::Class>( + WellKnownClasses::java_lang_BootClassLoader)->AllocObject(self)); + parent_field->SetObject<false>(h_class_loader.Get(), boot_loader); + } else { + parent_field->SetObject<false>(h_class_loader.Get(), parent_loader.Get()); + } + + ArtField* shared_libraries_field = + jni::DecodeArtField(WellKnownClasses::dalvik_system_BaseDexClassLoader_sharedLibraryLoaders); + DCHECK(shared_libraries_field != nullptr); + shared_libraries_field->SetObject<false>(h_class_loader.Get(), shared_libraries.Get()); - ObjPtr<mirror::Object> parent = (parent_loader != nullptr) - ? soa.Decode<mirror::ClassLoader>(parent_loader) - : soa.Decode<mirror::Class>(WellKnownClasses::java_lang_BootClassLoader)->AllocObject(self); - parent_field->SetObject<false>(h_class_loader.Get(), parent); + return h_class_loader.Get(); +} + +jobject ClassLinker::CreateWellKnownClassLoader(Thread* self, + const std::vector<const DexFile*>& dex_files, + jclass loader_class, + jobject parent_loader) { + CHECK(self->GetJniEnv()->IsSameObject(loader_class, + WellKnownClasses::dalvik_system_PathClassLoader) || + self->GetJniEnv()->IsSameObject(loader_class, + WellKnownClasses::dalvik_system_DelegateLastClassLoader)); + + // SOAAlreadyRunnable is protected, and we need something to add a global reference. + // We could move the jobject to the callers, but all call-sites do this... + ScopedObjectAccessUnchecked soa(self); + + // For now, create a libcore-level DexFile for each ART DexFile. This "explodes" multidex. + StackHandleScope<3> hs(self); + + Handle<mirror::Class> h_loader_class = + hs.NewHandle<mirror::Class>(soa.Decode<mirror::Class>(loader_class)); + Handle<mirror::ClassLoader> parent = + hs.NewHandle<mirror::ClassLoader>(ObjPtr<mirror::ClassLoader>::DownCast( + (parent_loader != nullptr) + ? soa.Decode<mirror::ClassLoader>(parent_loader) + : nullptr)); + Handle<mirror::ObjectArray<mirror::ClassLoader>> shared_libraries = + hs.NewHandle<mirror::ObjectArray<mirror::ClassLoader>>(nullptr); + + ObjPtr<mirror::ClassLoader> loader = CreateWellKnownClassLoader( + self, + dex_files, + h_loader_class, + shared_libraries, + parent); // Make it a global ref and return. ScopedLocalRef<jobject> local_ref( - soa.Env(), soa.Env()->AddLocalReference<jobject>(h_class_loader.Get())); + soa.Env(), soa.Env()->AddLocalReference<jobject>(loader)); return soa.Env()->NewGlobalRef(local_ref.get()); } diff --git a/runtime/class_linker.h b/runtime/class_linker.h index a65299a514..47931fec75 100644 --- a/runtime/class_linker.h +++ b/runtime/class_linker.h @@ -586,6 +586,16 @@ class ClassLinker { REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Locks::dex_lock_); + // Non-GlobalRef version of CreateWellKnownClassLoader + ObjPtr<mirror::ClassLoader> CreateWellKnownClassLoader( + Thread* self, + const std::vector<const DexFile*>& dex_files, + Handle<mirror::Class> loader_class, + Handle<mirror::ObjectArray<mirror::ClassLoader>> shared_libraries, + Handle<mirror::ClassLoader> parent_loader) + REQUIRES_SHARED(Locks::mutator_lock_) + REQUIRES(!Locks::dex_lock_); + PointerSize GetImagePointerSize() const { return image_pointer_size_; } diff --git a/runtime/class_loader_context.cc b/runtime/class_loader_context.cc index 0bae60a886..518be00bb5 100644 --- a/runtime/class_loader_context.cc +++ b/runtime/class_loader_context.cc @@ -24,11 +24,14 @@ #include "base/stl_util.h" #include "class_linker.h" #include "class_loader_utils.h" +#include "class_root.h" #include "dex/art_dex_file_loader.h" #include "dex/dex_file.h" #include "dex/dex_file_loader.h" #include "handle_scope-inl.h" #include "jni/jni_internal.h" +#include "mirror/object_array-alloc-inl.h" +#include "nativehelper/scoped_local_ref.h" #include "oat_file_assistant.h" #include "obj_ptr-inl.h" #include "runtime.h" @@ -571,20 +574,57 @@ static jclass GetClassLoaderClass(ClassLoaderContext::ClassLoaderType type) { UNREACHABLE(); } -static jobject CreateClassLoaderInternal(Thread* self, - const ClassLoaderContext::ClassLoaderInfo& info) +static ObjPtr<mirror::ClassLoader> CreateClassLoaderInternal( + Thread* self, + ScopedObjectAccess& soa, + const ClassLoaderContext::ClassLoaderInfo& info, + bool add_compilation_sources, + const std::vector<const DexFile*>& compilation_sources) REQUIRES_SHARED(Locks::mutator_lock_) { - CHECK(info.shared_libraries.empty()) << "Class loader shared library not implemented yet"; - jobject parent = nullptr; + StackHandleScope<3> hs(self); + MutableHandle<mirror::ObjectArray<mirror::ClassLoader>> libraries( + hs.NewHandle<mirror::ObjectArray<mirror::ClassLoader>>(nullptr)); + + if (!info.shared_libraries.empty()) { + libraries.Assign(mirror::ObjectArray<mirror::ClassLoader>::Alloc( + self, + GetClassRoot<mirror::ObjectArray<mirror::ClassLoader>>(), + info.shared_libraries.size())); + for (uint32_t i = 0; i < info.shared_libraries.size(); ++i) { + // We should only add the compilation sources to the first class loader. + libraries->Set(i, + CreateClassLoaderInternal( + self, + soa, + *info.shared_libraries[i].get(), + /* add_compilation_sources= */ false, + compilation_sources)); + } + } + + MutableHandle<mirror::ClassLoader> parent = hs.NewHandle<mirror::ClassLoader>(nullptr); if (info.parent != nullptr) { - parent = CreateClassLoaderInternal(self, *info.parent.get()); + // We should only add the compilation sources to the first class loader. + parent.Assign(CreateClassLoaderInternal( + self, soa, *info.parent.get(), /* add_compilation_sources= */ false, compilation_sources)); } std::vector<const DexFile*> class_path_files = MakeNonOwningPointerVector( info.opened_dex_files); + if (add_compilation_sources) { + // For the first class loader, its classpath comes first, followed by compilation sources. + // This ensures that whenever we need to resolve classes from it the classpath elements + // come first. + class_path_files.insert(class_path_files.end(), + compilation_sources.begin(), + compilation_sources.end()); + } + Handle<mirror::Class> loader_class = hs.NewHandle<mirror::Class>( + soa.Decode<mirror::Class>(GetClassLoaderClass(info.type))); return Runtime::Current()->GetClassLinker()->CreateWellKnownClassLoader( self, class_path_files, - GetClassLoaderClass(info.type), + loader_class, + libraries, parent); } @@ -598,30 +638,21 @@ jobject ClassLoaderContext::CreateClassLoader( ClassLinker* const class_linker = Runtime::Current()->GetClassLinker(); if (class_loader_chain_ == nullptr) { + CHECK(special_shared_library_); return class_linker->CreatePathClassLoader(self, compilation_sources); } // Create the class loader of the parent. - jobject parent = nullptr; - if (class_loader_chain_->parent != nullptr) { - parent = CreateClassLoaderInternal(self, *class_loader_chain_->parent.get()); - } - - // We set up all the parents. Move on to create the first class loader. - // Its classpath comes first, followed by compilation sources. This ensures that whenever - // we need to resolve classes from it the classpath elements come first. - - std::vector<const DexFile*> first_class_loader_classpath = MakeNonOwningPointerVector( - class_loader_chain_->opened_dex_files); - first_class_loader_classpath.insert(first_class_loader_classpath.end(), - compilation_sources.begin(), - compilation_sources.end()); - - return class_linker->CreateWellKnownClassLoader( - self, - first_class_loader_classpath, - GetClassLoaderClass(class_loader_chain_->type), - parent); + ObjPtr<mirror::ClassLoader> loader = + CreateClassLoaderInternal(self, + soa, + *class_loader_chain_.get(), + /* add_compilation_sources= */ true, + compilation_sources); + // Make it a global ref and return. + ScopedLocalRef<jobject> local_ref( + soa.Env(), soa.Env()->AddLocalReference<jobject>(loader)); + return soa.Env()->NewGlobalRef(local_ref.get()); } std::vector<const DexFile*> ClassLoaderContext::FlattenOpenedDexFiles() const { diff --git a/runtime/class_loader_context_test.cc b/runtime/class_loader_context_test.cc index f3e2ac00ba..dad07bd98d 100644 --- a/runtime/class_loader_context_test.cc +++ b/runtime/class_loader_context_test.cc @@ -19,12 +19,14 @@ #include <gtest/gtest.h> #include "android-base/strings.h" +#include "art_field-inl.h" #include "base/dchecked_vector.h" #include "base/stl_util.h" #include "class_linker.h" #include "common_runtime_test.h" #include "dex/dex_file.h" #include "handle_scope-inl.h" +#include "jni/jni_internal.h" #include "mirror/class.h" #include "mirror/class_loader.h" #include "mirror/object-inl.h" @@ -605,6 +607,292 @@ TEST_F(ClassLoaderContextTest, CreateClassLoaderWithComplexChain) { soa.Decode<mirror::Class>(WellKnownClasses::java_lang_BootClassLoader)); } +TEST_F(ClassLoaderContextTest, CreateClassLoaderWithSharedLibraries) { + // Setup the context. + std::vector<std::unique_ptr<const DexFile>> classpath_dex_a = OpenTestDexFiles("ForClassLoaderA"); + std::vector<std::unique_ptr<const DexFile>> classpath_dex_b = OpenTestDexFiles("ForClassLoaderB"); + std::vector<std::unique_ptr<const DexFile>> classpath_dex_c = OpenTestDexFiles("ForClassLoaderC"); + std::vector<std::unique_ptr<const DexFile>> classpath_dex_d = OpenTestDexFiles("ForClassLoaderD"); + + std::string context_spec = + "PCL[" + CreateClassPath(classpath_dex_a) + ":" + CreateClassPath(classpath_dex_b) + "]{" + + "DLC[" + CreateClassPath(classpath_dex_c) + "]#" + + "PCL[" + CreateClassPath(classpath_dex_d) + "]}"; + + std::unique_ptr<ClassLoaderContext> context = ClassLoaderContext::Create(context_spec); + ASSERT_TRUE(context->OpenDexFiles(InstructionSet::kArm, "")); + + // Setup the compilation sources. + std::vector<std::unique_ptr<const DexFile>> compilation_sources = OpenTestDexFiles("MultiDex"); + std::vector<const DexFile*> compilation_sources_raw = + MakeNonOwningPointerVector(compilation_sources); + + // Create the class loader. + jobject jclass_loader = context->CreateClassLoader(compilation_sources_raw); + ASSERT_TRUE(jclass_loader != nullptr); + + // Verify the class loader. + ScopedObjectAccess soa(Thread::Current()); + + StackHandleScope<4> hs(soa.Self()); + Handle<mirror::ClassLoader> class_loader_1 = hs.NewHandle( + soa.Decode<mirror::ClassLoader>(jclass_loader)); + + // For the first class loader the class path dex files must come first and then the + // compilation sources. + std::vector<const DexFile*> class_loader_1_dex_files = + MakeNonOwningPointerVector(classpath_dex_a); + for (auto& dex : classpath_dex_b) { + class_loader_1_dex_files.push_back(dex.get()); + } + for (auto& dex : compilation_sources_raw) { + class_loader_1_dex_files.push_back(dex); + } + VerifyClassLoaderDexFiles(soa, + class_loader_1, + WellKnownClasses::dalvik_system_PathClassLoader, + class_loader_1_dex_files); + + // Verify the shared libraries. + ArtField* field = + jni::DecodeArtField(WellKnownClasses::dalvik_system_BaseDexClassLoader_sharedLibraryLoaders); + ObjPtr<mirror::Object> raw_shared_libraries = field->GetObject(class_loader_1.Get()); + ASSERT_TRUE(raw_shared_libraries != nullptr); + + Handle<mirror::ObjectArray<mirror::ClassLoader>> shared_libraries( + hs.NewHandle(raw_shared_libraries->AsObjectArray<mirror::ClassLoader>())); + ASSERT_EQ(shared_libraries->GetLength(), 2); + + // Verify the first shared library. + Handle<mirror::ClassLoader> class_loader_2 = hs.NewHandle(shared_libraries->Get(0)); + std::vector<const DexFile*> class_loader_2_dex_files = + MakeNonOwningPointerVector(classpath_dex_c); + VerifyClassLoaderDexFiles(soa, + class_loader_2, + WellKnownClasses::dalvik_system_DelegateLastClassLoader, + class_loader_2_dex_files); + raw_shared_libraries = field->GetObject(class_loader_2.Get()); + ASSERT_TRUE(raw_shared_libraries == nullptr); + + // Verify the second shared library. + Handle<mirror::ClassLoader> class_loader_3 = hs.NewHandle(shared_libraries->Get(1)); + std::vector<const DexFile*> class_loader_3_dex_files = + MakeNonOwningPointerVector(classpath_dex_d); + VerifyClassLoaderDexFiles(soa, + class_loader_3, + WellKnownClasses::dalvik_system_PathClassLoader, + class_loader_3_dex_files); + raw_shared_libraries = field->GetObject(class_loader_3.Get()); + ASSERT_TRUE(raw_shared_libraries == nullptr); + + // All class loaders should have the BootClassLoader as a parent. + ASSERT_TRUE(class_loader_1->GetParent()->GetClass() == + soa.Decode<mirror::Class>(WellKnownClasses::java_lang_BootClassLoader)); + ASSERT_TRUE(class_loader_2->GetParent()->GetClass() == + soa.Decode<mirror::Class>(WellKnownClasses::java_lang_BootClassLoader)); + ASSERT_TRUE(class_loader_3->GetParent()->GetClass() == + soa.Decode<mirror::Class>(WellKnownClasses::java_lang_BootClassLoader)); +} + +TEST_F(ClassLoaderContextTest, CreateClassLoaderWithSharedLibrariesInParentToo) { + // Setup the context. + std::vector<std::unique_ptr<const DexFile>> classpath_dex_a = OpenTestDexFiles("ForClassLoaderA"); + std::vector<std::unique_ptr<const DexFile>> classpath_dex_b = OpenTestDexFiles("ForClassLoaderB"); + std::vector<std::unique_ptr<const DexFile>> classpath_dex_c = OpenTestDexFiles("ForClassLoaderC"); + std::vector<std::unique_ptr<const DexFile>> classpath_dex_d = OpenTestDexFiles("ForClassLoaderD"); + + std::string context_spec = + "PCL[" + CreateClassPath(classpath_dex_a) + "]{" + + "PCL[" + CreateClassPath(classpath_dex_b) + "]};" + + "PCL[" + CreateClassPath(classpath_dex_c) + "]{" + + "PCL[" + CreateClassPath(classpath_dex_d) + "]}"; + + std::unique_ptr<ClassLoaderContext> context = ClassLoaderContext::Create(context_spec); + ASSERT_TRUE(context->OpenDexFiles(InstructionSet::kArm, "")); + + // Setup the compilation sources. + std::vector<std::unique_ptr<const DexFile>> compilation_sources = OpenTestDexFiles("MultiDex"); + std::vector<const DexFile*> compilation_sources_raw = + MakeNonOwningPointerVector(compilation_sources); + + // Create the class loader. + jobject jclass_loader = context->CreateClassLoader(compilation_sources_raw); + ASSERT_TRUE(jclass_loader != nullptr); + + // Verify the class loader. + ScopedObjectAccess soa(Thread::Current()); + + StackHandleScope<6> hs(soa.Self()); + Handle<mirror::ClassLoader> class_loader_1 = hs.NewHandle( + soa.Decode<mirror::ClassLoader>(jclass_loader)); + + // For the first class loader the class path dex files must come first and then the + // compilation sources. + std::vector<const DexFile*> class_loader_1_dex_files = + MakeNonOwningPointerVector(classpath_dex_a); + for (auto& dex : compilation_sources_raw) { + class_loader_1_dex_files.push_back(dex); + } + VerifyClassLoaderDexFiles(soa, + class_loader_1, + WellKnownClasses::dalvik_system_PathClassLoader, + class_loader_1_dex_files); + + // Verify its shared library. + ArtField* field = + jni::DecodeArtField(WellKnownClasses::dalvik_system_BaseDexClassLoader_sharedLibraryLoaders); + ObjPtr<mirror::Object> raw_shared_libraries = field->GetObject(class_loader_1.Get()); + ASSERT_TRUE(raw_shared_libraries != nullptr); + + Handle<mirror::ObjectArray<mirror::ClassLoader>> shared_libraries( + hs.NewHandle(raw_shared_libraries->AsObjectArray<mirror::ClassLoader>())); + ASSERT_EQ(shared_libraries->GetLength(), 1); + + Handle<mirror::ClassLoader> class_loader_2 = hs.NewHandle(shared_libraries->Get(0)); + std::vector<const DexFile*> class_loader_2_dex_files = + MakeNonOwningPointerVector(classpath_dex_b); + VerifyClassLoaderDexFiles(soa, + class_loader_2, + WellKnownClasses::dalvik_system_PathClassLoader, + class_loader_2_dex_files); + raw_shared_libraries = field->GetObject(class_loader_2.Get()); + ASSERT_TRUE(raw_shared_libraries == nullptr); + + // Verify the parent. + Handle<mirror::ClassLoader> class_loader_3 = hs.NewHandle(class_loader_1->GetParent()); + std::vector<const DexFile*> class_loader_3_dex_files = + MakeNonOwningPointerVector(classpath_dex_c); + VerifyClassLoaderDexFiles(soa, + class_loader_3, + WellKnownClasses::dalvik_system_PathClassLoader, + class_loader_3_dex_files); + + // Verify its shared library. + raw_shared_libraries = field->GetObject(class_loader_3.Get()); + ASSERT_TRUE(raw_shared_libraries != nullptr); + + Handle<mirror::ObjectArray<mirror::ClassLoader>> shared_libraries_2( + hs.NewHandle(raw_shared_libraries->AsObjectArray<mirror::ClassLoader>())); + ASSERT_EQ(shared_libraries->GetLength(), 1); + + Handle<mirror::ClassLoader> class_loader_4 = hs.NewHandle(shared_libraries_2->Get(0)); + std::vector<const DexFile*> class_loader_4_dex_files = + MakeNonOwningPointerVector(classpath_dex_d); + VerifyClassLoaderDexFiles(soa, + class_loader_4, + WellKnownClasses::dalvik_system_PathClassLoader, + class_loader_4_dex_files); + raw_shared_libraries = field->GetObject(class_loader_4.Get()); + ASSERT_TRUE(raw_shared_libraries == nullptr); + + // Class loaders should have the BootClassLoader as a parent. + ASSERT_TRUE(class_loader_2->GetParent()->GetClass() == + soa.Decode<mirror::Class>(WellKnownClasses::java_lang_BootClassLoader)); + ASSERT_TRUE(class_loader_3->GetParent()->GetClass() == + soa.Decode<mirror::Class>(WellKnownClasses::java_lang_BootClassLoader)); + ASSERT_TRUE(class_loader_4->GetParent()->GetClass() == + soa.Decode<mirror::Class>(WellKnownClasses::java_lang_BootClassLoader)); +} + +TEST_F(ClassLoaderContextTest, CreateClassLoaderWithSharedLibrariesDependencies) { + // Setup the context. + std::vector<std::unique_ptr<const DexFile>> classpath_dex_a = OpenTestDexFiles("ForClassLoaderA"); + std::vector<std::unique_ptr<const DexFile>> classpath_dex_b = OpenTestDexFiles("ForClassLoaderB"); + std::vector<std::unique_ptr<const DexFile>> classpath_dex_c = OpenTestDexFiles("ForClassLoaderC"); + std::vector<std::unique_ptr<const DexFile>> classpath_dex_d = OpenTestDexFiles("ForClassLoaderD"); + + std::string context_spec = + "PCL[" + CreateClassPath(classpath_dex_a) + "]{" + + "PCL[" + CreateClassPath(classpath_dex_b) + "]{" + + "PCL[" + CreateClassPath(classpath_dex_c) + "]}};" + + "PCL[" + CreateClassPath(classpath_dex_d) + "]"; + + std::unique_ptr<ClassLoaderContext> context = ClassLoaderContext::Create(context_spec); + ASSERT_TRUE(context->OpenDexFiles(InstructionSet::kArm, "")); + + // Setup the compilation sources. + std::vector<std::unique_ptr<const DexFile>> compilation_sources = OpenTestDexFiles("MultiDex"); + std::vector<const DexFile*> compilation_sources_raw = + MakeNonOwningPointerVector(compilation_sources); + + // Create the class loader. + jobject jclass_loader = context->CreateClassLoader(compilation_sources_raw); + ASSERT_TRUE(jclass_loader != nullptr); + + // Verify the class loader. + ScopedObjectAccess soa(Thread::Current()); + + StackHandleScope<6> hs(soa.Self()); + Handle<mirror::ClassLoader> class_loader_1 = hs.NewHandle( + soa.Decode<mirror::ClassLoader>(jclass_loader)); + + // For the first class loader the class path dex files must come first and then the + // compilation sources. + std::vector<const DexFile*> class_loader_1_dex_files = + MakeNonOwningPointerVector(classpath_dex_a); + for (auto& dex : compilation_sources_raw) { + class_loader_1_dex_files.push_back(dex); + } + VerifyClassLoaderDexFiles(soa, + class_loader_1, + WellKnownClasses::dalvik_system_PathClassLoader, + class_loader_1_dex_files); + + // Verify its shared library. + ArtField* field = + jni::DecodeArtField(WellKnownClasses::dalvik_system_BaseDexClassLoader_sharedLibraryLoaders); + ObjPtr<mirror::Object> raw_shared_libraries = field->GetObject(class_loader_1.Get()); + ASSERT_TRUE(raw_shared_libraries != nullptr); + + Handle<mirror::ObjectArray<mirror::ClassLoader>> shared_libraries( + hs.NewHandle(raw_shared_libraries->AsObjectArray<mirror::ClassLoader>())); + ASSERT_EQ(shared_libraries->GetLength(), 1); + + Handle<mirror::ClassLoader> class_loader_2 = hs.NewHandle(shared_libraries->Get(0)); + std::vector<const DexFile*> class_loader_2_dex_files = + MakeNonOwningPointerVector(classpath_dex_b); + VerifyClassLoaderDexFiles(soa, + class_loader_2, + WellKnownClasses::dalvik_system_PathClassLoader, + class_loader_2_dex_files); + + // Verify the shared library dependency of the shared library. + raw_shared_libraries = field->GetObject(class_loader_2.Get()); + ASSERT_TRUE(raw_shared_libraries != nullptr); + + Handle<mirror::ObjectArray<mirror::ClassLoader>> shared_libraries_2( + hs.NewHandle(raw_shared_libraries->AsObjectArray<mirror::ClassLoader>())); + ASSERT_EQ(shared_libraries_2->GetLength(), 1); + + Handle<mirror::ClassLoader> class_loader_3 = hs.NewHandle(shared_libraries_2->Get(0)); + std::vector<const DexFile*> class_loader_3_dex_files = + MakeNonOwningPointerVector(classpath_dex_c); + VerifyClassLoaderDexFiles(soa, + class_loader_3, + WellKnownClasses::dalvik_system_PathClassLoader, + class_loader_3_dex_files); + raw_shared_libraries = field->GetObject(class_loader_3.Get()); + ASSERT_TRUE(raw_shared_libraries == nullptr); + + // Verify the parent. + Handle<mirror::ClassLoader> class_loader_4 = hs.NewHandle(class_loader_1->GetParent()); + std::vector<const DexFile*> class_loader_4_dex_files = + MakeNonOwningPointerVector(classpath_dex_d); + VerifyClassLoaderDexFiles(soa, + class_loader_4, + WellKnownClasses::dalvik_system_PathClassLoader, + class_loader_4_dex_files); + raw_shared_libraries = field->GetObject(class_loader_4.Get()); + ASSERT_TRUE(raw_shared_libraries == nullptr); + + // Class loaders should have the BootClassLoader as a parent. + ASSERT_TRUE(class_loader_2->GetParent()->GetClass() == + soa.Decode<mirror::Class>(WellKnownClasses::java_lang_BootClassLoader)); + ASSERT_TRUE(class_loader_3->GetParent()->GetClass() == + soa.Decode<mirror::Class>(WellKnownClasses::java_lang_BootClassLoader)); + ASSERT_TRUE(class_loader_4->GetParent()->GetClass() == + soa.Decode<mirror::Class>(WellKnownClasses::java_lang_BootClassLoader)); +} TEST_F(ClassLoaderContextTest, RemoveSourceLocations) { std::unique_ptr<ClassLoaderContext> context = diff --git a/runtime/class_root.h b/runtime/class_root.h index 1cd135f2aa..1ff48457d6 100644 --- a/runtime/class_root.h +++ b/runtime/class_root.h @@ -101,6 +101,7 @@ class VarHandle; M(kLongArrayClass, "[J", mirror::PrimitiveArray<int64_t>) \ M(kShortArrayClass, "[S", mirror::PrimitiveArray<int16_t>) \ M(kJavaLangStackTraceElementArrayClass, "[Ljava/lang/StackTraceElement;", mirror::ObjectArray<mirror::StackTraceElement>) \ + M(kJavaLangClassLoaderArrayClass, "[Ljava/lang/ClassLoader;", mirror::ObjectArray<mirror::ClassLoader>) \ M(kDalvikSystemClassExt, "Ldalvik/system/ClassExt;", mirror::ClassExt) // Well known mirror::Class roots accessed via ClassLinker::GetClassRoots(). |