Create a class loader context starting from an existing ClassLoader

Extend ClassLoaderContext to be able to generate a context from an
existing class loader.

This will be used in extending the duplicate class check to cover
DelegateLastClassLoaders.

Most of the functionality is migrated from OatFileManager with some
cleanups consisting of extra docs and more conservative checks on the
integrity of the class loader chain.

Test: m test-art-host
Bug: 38138251
Change-Id: If7c18cb75bfc9e6784676f96a666bf13b04c8b8b
diff --git a/runtime/class_loader_context.h b/runtime/class_loader_context.h
index 9727a3b..81c8903 100644
--- a/runtime/class_loader_context.h
+++ b/runtime/class_loader_context.h
@@ -22,7 +22,9 @@
 
 #include "arch/instruction_set.h"
 #include "base/dchecked_vector.h"
-#include "jni.h"
+#include "handle_scope.h"
+#include "mirror/class_loader.h"
+#include "scoped_thread_state_change.h"
 
 namespace art {
 
@@ -35,6 +37,8 @@
   // Creates an empty context (with no class loaders).
   ClassLoaderContext();
 
+  ~ClassLoaderContext();
+
   // Opens requested class path files and appends them to ClassLoaderInfo::opened_dex_files.
   // If the dex files have been stripped, the method opens them from their oat files which are added
   // to ClassLoaderInfo::opened_oat_files. The 'classpath_dir' argument specifies the directory to
@@ -93,6 +97,16 @@
       std::vector<uint32_t>* out_checksums,
       bool* out_is_special_shared_library);
 
+  // Creates a context for the given class_loader and dex_elements.
+  // The method will walk the parent chain starting from `class_loader` and add their dex files
+  // to the current class loaders chain. The `dex_elements` will be added at the end of the
+  // classpath belonging to the `class_loader` argument.
+  // The ownership of the opened dex files will be retained by the given `class_loader`.
+  // If there are errors in processing the class loader chain (e.g. unsupported elements) the
+  // method returns null.
+  static std::unique_ptr<ClassLoaderContext> CreateContextForClassLoader(jobject class_loader,
+                                                                         jobjectArray dex_elements);
+
  private:
   enum ClassLoaderType {
     kInvalidClassLoader = 0,
@@ -118,6 +132,13 @@
     explicit ClassLoaderInfo(ClassLoaderType cl_type) : type(cl_type) {}
   };
 
+  // Constructs an empty context.
+  // `owns_the_dex_files` specifies whether or not the context will own the opened dex files
+  // present in the class loader chain. If `owns_the_dex_files` is true then OpenDexFiles cannot
+  // be called on this context (dex_files_open_attempted_ and dex_files_open_result_ will be set
+  // to true as well)
+  explicit ClassLoaderContext(bool owns_the_dex_files);
+
   // Reads the class loader spec in place and returns true if the spec is valid and the
   // compilation context was constructed.
   bool Parse(const std::string& spec, bool parse_checksums = false);
@@ -129,6 +150,19 @@
                             ClassLoaderType class_loader_type,
                             bool parse_checksums = false);
 
+  // CHECKs that the dex files were opened (OpenDexFiles was called and set dex_files_open_result_
+  // to true). Aborts if not. The `calling_method` is used in the log message to identify the source
+  // of the call.
+  void CheckDexFilesOpened(const std::string& calling_method) const;
+
+  // Adds the `class_loader` info to the context.
+  // The dex file present in `dex_elements` array (if not null) will be added at the end of
+  // the classpath.
+  bool AddInfoToContextFromClassLoader(ScopedObjectAccessAlreadyRunnable& soa,
+                                       Handle<mirror::ClassLoader> class_loader,
+                                       Handle<mirror::ObjectArray<mirror::Object>> dex_elements)
+  REQUIRES_SHARED(Locks::mutator_lock_);
+
   // Extracts the class loader type from the given spec.
   // Return ClassLoaderContext::kInvalidClassLoader if the class loader type is not
   // recognized.
@@ -138,9 +172,6 @@
   // The returned format can be used when parsing a context spec.
   static const char* GetClassLoaderTypeName(ClassLoaderType type);
 
-  // CHECKs that the dex files were opened (OpenDexFiles was called). Aborts if not.
-  void CheckDexFilesOpened(const std::string& calling_method) const;
-
   // The class loader chain represented as a vector.
   // The parent of class_loader_chain_[i] is class_loader_chain_[i++].
   // The parent of the last element is assumed to be the boot class loader.
@@ -158,6 +189,13 @@
   // The result of the last OpenDexFiles() operation.
   bool dex_files_open_result_;
 
+  // Whether or not the context owns the opened dex and oat files.
+  // If true, the opened dex files will be de-allocated when the context is destructed.
+  // If false, the objects will continue to be alive.
+  // Note that for convenience the the opened dex/oat files are stored as unique pointers
+  // which will release their ownership in the destructor based on this flag.
+  const bool owns_the_dex_files_;
+
   friend class ClassLoaderContextTest;
 
   DISALLOW_COPY_AND_ASSIGN(ClassLoaderContext);