Add support for shared libaries in class loader context.

For example:
PCL[a.dex:b.dex]{PCL[s1.dex]#PCL[s2.dex:s3.dex]};DLC[c.dex:d.dex]{DLC[s4.dex]}

Rewrite the class_loader_chain_ to be a chain instead of a vector,
to simplify processing and encoding of contexts.

bug: 111174995
Test: class_loader_context_test, test.py
Change-Id: I7c9f71b67a91b43ae534721b43dc4fdb8e0b6ec4
diff --git a/runtime/class_loader_context.h b/runtime/class_loader_context.h
index a4268aa..37cef81 100644
--- a/runtime/class_loader_context.h
+++ b/runtime/class_loader_context.h
@@ -154,10 +154,11 @@
   // This will return a context with a single and empty PathClassLoader.
   static std::unique_ptr<ClassLoaderContext> Default();
 
- private:
   struct ClassLoaderInfo {
     // The type of this class loader.
     ClassLoaderType type;
+    // Shared libraries this context has.
+    std::vector<std::unique_ptr<ClassLoaderInfo>> shared_libraries;
     // The list of class path elements that this loader loads.
     // Note that this list may contain relative paths.
     std::vector<std::string> classpath;
@@ -171,13 +172,35 @@
     // After OpenDexFiles, in case some of the dex files were opened from their oat files
     // this holds the list of opened oat files.
     std::vector<std::unique_ptr<OatFile>> opened_oat_files;
+    // The parent class loader.
+    std::unique_ptr<ClassLoaderInfo> parent;
 
     explicit ClassLoaderInfo(ClassLoaderType cl_type) : type(cl_type) {}
   };
 
+ private:
   // Creates an empty context (with no class loaders).
   ClassLoaderContext();
 
+  // Get the parent of the class loader chain at depth `index`.
+  ClassLoaderInfo* GetParent(size_t index) const {
+    ClassLoaderInfo* result = class_loader_chain_.get();
+    while ((result != nullptr) && (index-- != 0)) {
+      result = result->parent.get();
+    }
+    return result;
+  }
+
+  size_t GetParentChainSize() const {
+    size_t result = 0;
+    ClassLoaderInfo* info = class_loader_chain_.get();
+    while (info != nullptr) {
+      ++result;
+      info = info->parent.get();
+    }
+    return result;
+  }
+
   // 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
@@ -188,13 +211,13 @@
   // 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);
+  ClassLoaderInfo* ParseInternal(const std::string& spec, bool parse_checksums);
 
-  // Attempts to parse a single class loader spec for the given class_loader_type.
-  // If successful the class loader spec will be added to the chain.
-  // Returns whether or not the operation was successful.
-  bool ParseClassLoaderSpec(const std::string& class_loader_spec,
-                            ClassLoaderType class_loader_type,
-                            bool parse_checksums = false);
+  // Attempts to parse a single class loader spec.
+  // Returns the ClassLoaderInfo abstraction for this spec, or null if it cannot be parsed.
+  std::unique_ptr<ClassLoaderInfo> ParseClassLoaderSpec(
+      const std::string& class_loader_spec,
+      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
@@ -219,6 +242,20 @@
                             bool for_dex2oat,
                             ClassLoaderContext* stored_context) const;
 
+  // Internal version of `EncodeContext`, which will be called recursively
+  // on the parent and shared libraries.
+  void EncodeContextInternal(const ClassLoaderInfo& info,
+                             const std::string& base_dir,
+                             bool for_dex2oat,
+                             ClassLoaderInfo* stored_info,
+                             std::ostringstream& out) const;
+
+  bool ClassLoaderInfoMatch(const ClassLoaderInfo& info,
+                            const ClassLoaderInfo& expected_info,
+                            const std::string& context_spec,
+                            bool verify_names,
+                            bool verify_checksums) const;
+
   // Extracts the class loader type from the given spec.
   // Return ClassLoaderContext::kInvalidClassLoader if the class loader type is not
   // recognized.
@@ -228,13 +265,8 @@
   // The returned format can be used when parsing a context spec.
   static const char* GetClassLoaderTypeName(ClassLoaderType type);
 
-  // Returns the WellKnownClass for the given class loader type.
-  static jclass GetClassLoaderClass(ClassLoaderType type);
-
-  // 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.
-  std::vector<ClassLoaderInfo> class_loader_chain_;
+  // The class loader chain.
+  std::unique_ptr<ClassLoaderInfo> class_loader_chain_;
 
   // Whether or not the class loader context should be ignored at runtime when loading the oat
   // files. When true, dex2oat will use OatFile::kSpecialSharedLibrary as the classpath key in