Support shared libraries in ClassLoaderContext::CreateClassLoader.
bug: 111174995
Test: dex2oat_test, class_loader_context_test
Change-Id: I482012eca408f9e064d7c3d787662376e1b0de3b
diff --git a/dex2oat/dex2oat_test.cc b/dex2oat/dex2oat_test.cc
index baeebd9..1fa21d5 100644
--- a/dex2oat/dex2oat_test.cc
+++ b/dex2oat/dex2oat_test.cc
@@ -1202,6 +1202,17 @@
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 35379cc..9e31a20 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -798,6 +798,8 @@
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 @@
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));
+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) {
- // 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<6> hs(self);
+ StackHandleScope<5> hs(self);
ArtField* dex_elements_field =
jni::DecodeArtField(WellKnownClasses::dalvik_system_DexPathList_dexElements);
@@ -9109,8 +9104,8 @@
}
// 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 @@
"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());
+ }
- 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);
+ 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());
+
+ 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 a65299a..47931fe 100644
--- a/runtime/class_linker.h
+++ b/runtime/class_linker.h
@@ -586,6 +586,16 @@
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 0bae60a..518be00 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 @@
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 @@
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 f3e2ac0..dad07bd 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 @@
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 1cd135f..1ff4845 100644
--- a/runtime/class_root.h
+++ b/runtime/class_root.h
@@ -101,6 +101,7 @@
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().