Add support to place shared libraries after the dex path

This allows for a shared library to overriden by content in the dex path

Bug: 179429740

Test: m test-art-host-gtest-art_runtime_tests32

Change-Id: I5f69c7bf32b7bd389eff8bdbb21616ba89ed9e87
diff --git a/runtime/class_loader_context.cc b/runtime/class_loader_context.cc
index 228b950..318d117 100644
--- a/runtime/class_loader_context.cc
+++ b/runtime/class_loader_context.cc
@@ -56,6 +56,7 @@
 static constexpr char kClassLoaderSharedLibraryOpeningMark = '{';
 static constexpr char kClassLoaderSharedLibraryClosingMark = '}';
 static constexpr char kClassLoaderSharedLibrarySeparator = '#';
+static constexpr char kClassLoaderSharedLibraryAfterSeparator = '~';
 static constexpr char kClassLoaderSeparator = ';';
 static constexpr char kClasspathSeparator = ':';
 static constexpr char kDexFileChecksumSeparator = '*';
@@ -80,6 +81,9 @@
   for (size_t i = 0; i < info->shared_libraries.size(); ++i) {
     work_list.push_back(info->shared_libraries[i].get());
   }
+  for (size_t i = 0; i < info->shared_libraries_after.size(); ++i) {
+    work_list.push_back(info->shared_libraries_after[i].get());
+  }
 }
 
 ClassLoaderContext::~ClassLoaderContext() {
@@ -239,6 +243,7 @@
     std::vector<std::string> shared_libraries;
     size_t cursor = 0;
     while (cursor != shared_libraries_spec.length()) {
+      bool is_after = false;
       size_t shared_library_separator =
           shared_libraries_spec.find_first_of(kClassLoaderSharedLibrarySeparator, cursor);
       size_t shared_library_open =
@@ -247,6 +252,12 @@
       if (shared_library_separator == std::string::npos) {
         // Only one shared library, for example:
         // PCL[...]
+        if (shared_libraries_spec[cursor] == kClassLoaderSharedLibraryAfterSeparator) {
+          // This library was marked to be loaded after the dex path
+          is_after = true;
+          // Pass the shared library after separator marker.
+          ++cursor;
+        }
         shared_library_spec =
             shared_libraries_spec.substr(cursor, shared_libraries_spec.length() - cursor);
         cursor = shared_libraries_spec.length();
@@ -254,6 +265,12 @@
                  (shared_library_open > shared_library_separator)) {
         // We found a shared library without nested shared libraries, for example:
         // PCL[...]#PCL[...]{...}
+        if (shared_libraries_spec[cursor] == kClassLoaderSharedLibraryAfterSeparator) {
+          // This library was marked to be loaded after the dex path
+          is_after = true;
+          // Pass the shared library after separator marker.
+          ++cursor;
+        }
         shared_library_spec =
             shared_libraries_spec.substr(cursor, shared_library_separator - cursor);
         cursor = shared_library_separator + 1;
@@ -266,6 +283,12 @@
           // No matching closing marker, return an error.
           return nullptr;
         }
+        if (shared_libraries_spec[cursor] == kClassLoaderSharedLibraryAfterSeparator) {
+          // This library was marked to be loaded after the dex path
+          is_after = true;
+          // Pass the shared library after separator marker.
+          ++cursor;
+        }
         shared_library_spec = shared_libraries_spec.substr(cursor, closing_marker + 1 - cursor);
         cursor = closing_marker + 1;
         if (cursor != shared_libraries_spec.length() &&
@@ -274,12 +297,17 @@
           ++cursor;
         }
       }
-      std::unique_ptr<ClassLoaderInfo> shared_library(
-          ParseInternal(shared_library_spec, parse_checksums));
-      if (shared_library == nullptr) {
+
+      std::unique_ptr<ClassLoaderInfo> shared_library_info(
+                ParseInternal(shared_library_spec, parse_checksums));
+      if (shared_library_info == nullptr) {
         return nullptr;
       }
-      info->shared_libraries.push_back(std::move(shared_library));
+      if (is_after) {
+        info->shared_libraries_after.push_back(std::move(shared_library_info));
+      } else {
+        info->shared_libraries.push_back(std::move(shared_library_info));
+      }
     }
   }
 
@@ -709,7 +737,7 @@
                                                   bool for_dex2oat,
                                                   ClassLoaderInfo* stored_info,
                                                   std::ostringstream& out) const {
-  if (!info.shared_libraries.empty()) {
+  if (!info.shared_libraries.empty() || !info.shared_libraries_after.empty()) {
     out << kClassLoaderSharedLibraryOpeningMark;
     for (uint32_t i = 0; i < info.shared_libraries.size(); ++i) {
       if (i > 0) {
@@ -722,6 +750,20 @@
           (stored_info == nullptr ? nullptr : stored_info->shared_libraries[i].get()),
           out);
     }
+
+    for (uint32_t i = 0; i < info.shared_libraries_after.size(); ++i) {
+      if (i > 0 || !info.shared_libraries.empty()) {
+        out << kClassLoaderSharedLibrarySeparator;
+      }
+      out << kClassLoaderSharedLibraryAfterSeparator;
+      EncodeContextInternal(
+          *info.shared_libraries_after[i].get(),
+          base_dir,
+          for_dex2oat,
+          (stored_info == nullptr ? nullptr : stored_info->shared_libraries_after[i].get()),
+          out);
+    }
+
     out << kClassLoaderSharedLibraryClosingMark;
   }
   if (info.parent != nullptr) {
@@ -772,9 +814,11 @@
     }
   }
 
-  StackHandleScope<3> hs(self);
+  StackHandleScope<4> hs(self);
   MutableHandle<mirror::ObjectArray<mirror::ClassLoader>> libraries(
       hs.NewHandle<mirror::ObjectArray<mirror::ClassLoader>>(nullptr));
+  MutableHandle<mirror::ObjectArray<mirror::ClassLoader>> libraries_after(
+        hs.NewHandle<mirror::ObjectArray<mirror::ClassLoader>>(nullptr));
 
   if (!info.shared_libraries.empty()) {
     libraries.Assign(mirror::ObjectArray<mirror::ClassLoader>::Alloc(
@@ -796,6 +840,26 @@
     }
   }
 
+  if (!info.shared_libraries_after.empty()) {
+    libraries_after.Assign(mirror::ObjectArray<mirror::ClassLoader>::Alloc(
+        self,
+        GetClassRoot<mirror::ObjectArray<mirror::ClassLoader>>(),
+        info.shared_libraries_after.size()));
+    for (uint32_t i = 0; i < info.shared_libraries_after.size(); ++i) {
+      // We should only add the compilation sources to the first class loader.
+      libraries_after->Set(i,
+                     CreateClassLoaderInternal(
+                         self,
+                         soa,
+                         *info.shared_libraries_after[i].get(),
+                         /* for_shared_library= */ true,
+                         map_scope,
+                         canonicalized_libraries,
+                         /* add_compilation_sources= */ false,
+                         compilation_sources));
+    }
+  }
+
   MutableHandle<mirror::ClassLoader> parent = hs.NewHandle<mirror::ClassLoader>(nullptr);
   if (info.parent != nullptr) {
     // We should only add the compilation sources to the first class loader.
@@ -827,7 +891,8 @@
           class_path_files,
           loader_class,
           parent,
-          libraries);
+          libraries,
+          libraries_after);
   if (for_shared_library) {
     canonicalized_libraries[FlattenClasspath(info.classpath)] =
         map_scope.NewHandle<mirror::ClassLoader>(loader);
@@ -1063,7 +1128,8 @@
       Handle<mirror::ClassLoader> class_loader,
       Handle<mirror::ObjectArray<mirror::Object>> dex_elements,
       ClassLoaderInfo* child_info,
-      bool is_shared_library)
+      bool is_shared_library,
+      bool is_after)
     REQUIRES_SHARED(Locks::mutator_lock_) {
   if (ClassLinker::IsBootClassLoader(soa, class_loader.Get())) {
     // Nothing to do for the boot class loader as we don't add its dex files to the context.
@@ -1105,7 +1171,11 @@
   if (child_info == nullptr) {
     class_loader_chain_.reset(info);
   } else if (is_shared_library) {
-    child_info->shared_libraries.push_back(std::unique_ptr<ClassLoaderInfo>(info));
+    if (is_after) {
+      child_info->shared_libraries_after.push_back(std::unique_ptr<ClassLoaderInfo>(info));
+    } else {
+      child_info->shared_libraries.push_back(std::unique_ptr<ClassLoaderInfo>(info));
+    }
   } else {
     child_info->parent.reset(info);
   }
@@ -1126,7 +1196,7 @@
   ScopedNullHandle<mirror::ObjectArray<mirror::Object>> null_dex_elements;
 
   // Add the shared libraries.
-  StackHandleScope<3> hs(Thread::Current());
+  StackHandleScope<5> hs(Thread::Current());
   ArtField* field =
       jni::DecodeArtField(WellKnownClasses::dalvik_system_BaseDexClassLoader_sharedLibraryLoaders);
   ObjPtr<mirror::Object> raw_shared_libraries = field->GetObject(class_loader.Get());
@@ -1136,8 +1206,31 @@
     MutableHandle<mirror::ClassLoader> temp_loader = hs.NewHandle<mirror::ClassLoader>(nullptr);
     for (auto library : shared_libraries.Iterate<mirror::ClassLoader>()) {
       temp_loader.Assign(library);
-      if (!CreateInfoFromClassLoader(
-              soa, temp_loader, null_dex_elements, info, /*is_shared_library=*/ true)) {
+      if (!CreateInfoFromClassLoader(soa,
+                                     temp_loader,
+                                     null_dex_elements,
+                                     info,
+                                     /*is_shared_library=*/ true,
+                                     /*is_after=*/ false)) {
+        return false;
+      }
+    }
+  }
+  ArtField* field2 = jni::DecodeArtField(
+      WellKnownClasses::dalvik_system_BaseDexClassLoader_sharedLibraryLoadersAfter);
+  ObjPtr<mirror::Object> raw_shared_libraries_after = field2->GetObject(class_loader.Get());
+  if (raw_shared_libraries_after != nullptr) {
+    Handle<mirror::ObjectArray<mirror::ClassLoader>> shared_libraries_after =
+        hs.NewHandle(raw_shared_libraries_after->AsObjectArray<mirror::ClassLoader>());
+    MutableHandle<mirror::ClassLoader> temp_loader = hs.NewHandle<mirror::ClassLoader>(nullptr);
+    for (auto library : shared_libraries_after.Iterate<mirror::ClassLoader>()) {
+      temp_loader.Assign(library);
+      if (!CreateInfoFromClassLoader(soa,
+                                     temp_loader,
+                                     null_dex_elements,
+                                     info,
+                                     /*is_shared_library=*/ true,
+                                     /*is_after=*/ true)) {
         return false;
       }
     }
@@ -1145,8 +1238,12 @@
 
   // We created the ClassLoaderInfo for the current loader. Move on to its parent.
   Handle<mirror::ClassLoader> parent = hs.NewHandle(class_loader->GetParent());
-  if (!CreateInfoFromClassLoader(
-          soa, parent, null_dex_elements, info, /*is_shared_library=*/ false)) {
+  if (!CreateInfoFromClassLoader(soa,
+                                 parent,
+                                 null_dex_elements,
+                                 info,
+                                 /*is_shared_library=*/ false,
+                                 /*is_after=*/ false)) {
     return false;
   }
   return true;
@@ -1167,8 +1264,12 @@
   Handle<mirror::ObjectArray<mirror::Object>> h_dex_elements =
       hs.NewHandle(soa.Decode<mirror::ObjectArray<mirror::Object>>(dex_elements));
   std::unique_ptr<ClassLoaderContext> result(new ClassLoaderContext(/*owns_the_dex_files=*/ false));
-  if (!result->CreateInfoFromClassLoader(
-          soa, h_class_loader, h_dex_elements, nullptr, /*is_shared_library=*/ false)) {
+  if (!result->CreateInfoFromClassLoader(soa,
+                                         h_class_loader,
+                                         h_dex_elements,
+                                         nullptr,
+                                         /*is_shared_library=*/ false,
+                                         /*is_after=*/ false)) {
     return nullptr;
   }
   return result;