Pass the class loader context to dex2oat when optimizing at runtime

Until now we always passed the special shared library symbol "&" when we
called dex2oat at runtime without an explicit class path.

This CL changes that and passes the class loader context inferred from the
runtime class loaders to dex2oat. If any of the runtime class loaders is
not supported we continue to pass the special library symbol.

Bug: 38138251
Test: m test-art-host
Change-Id: Ica43ee8a3f36dab2d9ed0e634a9f6341379c8e1c
diff --git a/runtime/class_loader_context.h b/runtime/class_loader_context.h
index 37dd02b..85299d4 100644
--- a/runtime/class_loader_context.h
+++ b/runtime/class_loader_context.h
@@ -82,9 +82,16 @@
   // (so that it can be read and verified at runtime against the actual class
   // loader hierarchy).
   // Should only be called if OpenDexFiles() returned true.
-  // E.g. if the context is PCL[a.dex:b.dex] this will return "a.dex*a_checksum*b.dex*a_checksum".
+  // E.g. if the context is PCL[a.dex:b.dex] this will return
+  // "PCL[a.dex*a_checksum*b.dex*a_checksum]".
   std::string EncodeContextForOatFile(const std::string& base_dir) const;
 
+  // Encodes the context as a string suitable to be passed to dex2oat.
+  // This is the same as EncodeContextForOatFile but without adding the checksums
+  // and only adding each dex files once (no multidex).
+  // Should only be called if OpenDexFiles() returned true.
+  std::string EncodeContextForDex2oat(const std::string& base_dir) const;
+
   // Flattens the opened dex files into the given vector.
   // Should only be called if OpenDexFiles() returned true.
   std::vector<const DexFile*> FlattenOpenedDexFiles() const;
@@ -94,7 +101,7 @@
   //    - the number and type of the class loaders from the chain matches
   //    - the class loader from the same position have the same classpath
   //      (the order and checksum of the dex files matches)
-  bool VerifyClassLoaderContextMatch(const std::string& context_spec);
+  bool VerifyClassLoaderContextMatch(const std::string& context_spec) const;
 
   // Creates the class loader context from the given string.
   // The format: ClassLoaderType1[ClasspathElem1:ClasspathElem2...];ClassLoaderType2[...]...
@@ -173,7 +180,15 @@
   bool AddInfoToContextFromClassLoader(ScopedObjectAccessAlreadyRunnable& soa,
                                        Handle<mirror::ClassLoader> class_loader,
                                        Handle<mirror::ObjectArray<mirror::Object>> dex_elements)
-  REQUIRES_SHARED(Locks::mutator_lock_);
+    REQUIRES_SHARED(Locks::mutator_lock_);
+
+  // Encodes the context as a string suitable to be passed to dex2oat or to be added to the
+  // oat file as the class path key.
+  // If for_dex2oat is true, the encoding adds each file once (i.e. it does not add multidex
+  // location). Otherwise, for oat files, the encoding adds all the dex files (including multidex)
+  // together with their checksums.
+  // Should only be called if OpenDexFiles() returned true.
+  std::string EncodeContext(const std::string& base_dir, bool for_dex2oat) const;
 
   // Extracts the class loader type from the given spec.
   // Return ClassLoaderContext::kInvalidClassLoader if the class loader type is not