Allow dex2oat to create a full class loader context

We previously checked that dex2oat sees only a single class loader. This
CL removes the restriction and enables dex2oat to create and compile with
a full class loader context.

Test: m test-art-host
Bug: 38138251
Change-Id: I03e75a75757995ce8ce3addf0bc0a708e18ac050
diff --git a/runtime/class_loader_context.cc b/runtime/class_loader_context.cc
index 678ae8f..90346f0 100644
--- a/runtime/class_loader_context.cc
+++ b/runtime/class_loader_context.cc
@@ -305,24 +305,41 @@
   Thread* self = Thread::Current();
   ScopedObjectAccess soa(self);
 
-  std::vector<const DexFile*> class_path_files;
+  ClassLinker* const class_linker = Runtime::Current()->GetClassLinker();
 
-  // TODO(calin): Transition period: assume we only have a classloader until
-  // the oat file assistant implements the full class loader check.
-  if (!class_loader_chain_.empty()) {
-    CHECK_EQ(1u, class_loader_chain_.size());
-    CHECK_EQ(kPathClassLoader, class_loader_chain_[0].type);
-    class_path_files = MakeNonOwningPointerVector(class_loader_chain_[0].opened_dex_files);
+  if (class_loader_chain_.empty()) {
+    return class_linker->CreatePathClassLoader(self, compilation_sources);
   }
 
-  // Classpath: first the class-path given; then the dex files we'll compile.
-  // Thus we'll resolve the class-path first.
-  class_path_files.insert(class_path_files.end(),
-                          compilation_sources.begin(),
-                          compilation_sources.end());
+  // Create the class loaders starting from the top most parent (the one on the last position
+  // in the chain) but omit the first class loader which will contain the compilation_sources and
+  // needs special handling.
+  jobject current_parent = nullptr;  // the starting parent is the BootClassLoader.
+  for (size_t i = class_loader_chain_.size() - 1; i > 0; i--) {
+    std::vector<const DexFile*> class_path_files = MakeNonOwningPointerVector(
+        class_loader_chain_[i].opened_dex_files);
+    current_parent = class_linker->CreateWellKnownClassLoader(
+        self,
+        class_path_files,
+        GetClassLoaderClass(class_loader_chain_[i].type),
+        current_parent);
+  }
 
-  ClassLinker* const class_linker = Runtime::Current()->GetClassLinker();
-  return class_linker->CreatePathClassLoader(self, class_path_files);
+  // 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_[0].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_[0].type),
+      current_parent);
 }
 
 std::vector<const DexFile*> ClassLoaderContext::FlattenOpenedDexFiles() const {
@@ -623,5 +640,15 @@
   return true;
 }
 
+jclass ClassLoaderContext::GetClassLoaderClass(ClassLoaderType type) {
+  switch (type) {
+    case kPathClassLoader: return WellKnownClasses::dalvik_system_PathClassLoader;
+    case kDelegateLastClassLoader: return WellKnownClasses::dalvik_system_DelegateLastClassLoader;
+    case kInvalidClassLoader: break;  // will fail after the switch.
+  }
+  LOG(FATAL) << "Invalid class loader type " << type;
+  UNREACHABLE();
+}
+
 }  // namespace art