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_linker.cc b/runtime/class_linker.cc
index 0d50dd3..4875298 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -2612,6 +2612,16 @@
                                              /*out*/ ObjPtr<mirror::Class>* result) {
   ArtField* field =
       jni::DecodeArtField(WellKnownClasses::dalvik_system_BaseDexClassLoader_sharedLibraryLoaders);
+  return FindClassInSharedLibrariesHelper(soa, self, descriptor, hash, class_loader, field, result);
+}
+
+bool ClassLinker::FindClassInSharedLibrariesHelper(ScopedObjectAccessAlreadyRunnable& soa,
+                                                   Thread* self,
+                                                   const char* descriptor,
+                                                   size_t hash,
+                                                   Handle<mirror::ClassLoader> class_loader,
+                                                   ArtField* field,
+                                                   /*out*/ ObjPtr<mirror::Class>* result) {
   ObjPtr<mirror::Object> raw_shared_libraries = field->GetObject(class_loader.Get());
   if (raw_shared_libraries == nullptr) {
     return true;
@@ -2631,6 +2641,17 @@
   return true;
 }
 
+bool ClassLinker::FindClassInSharedLibrariesAfter(ScopedObjectAccessAlreadyRunnable& soa,
+                                                  Thread* self,
+                                                  const char* descriptor,
+                                                  size_t hash,
+                                                  Handle<mirror::ClassLoader> class_loader,
+                                                  /*out*/ ObjPtr<mirror::Class>* result) {
+  ArtField* field = jni::DecodeArtField(
+      WellKnownClasses::dalvik_system_BaseDexClassLoader_sharedLibraryLoadersAfter);
+  return FindClassInSharedLibrariesHelper(soa, self, descriptor, hash, class_loader, field, result);
+}
+
 bool ClassLinker::FindClassInBaseDexClassLoader(ScopedObjectAccessAlreadyRunnable& soa,
                                                 Thread* self,
                                                 const char* descriptor,
@@ -2665,6 +2686,10 @@
         FindClassInBaseDexClassLoaderClassPath(soa, descriptor, hash, class_loader, result),
         *result,
         self);
+    RETURN_IF_UNRECOGNIZED_OR_FOUND_OR_EXCEPTION(
+        FindClassInSharedLibrariesAfter(soa, self, descriptor, hash, class_loader, result),
+        *result,
+        self);
     // We did not find a class, but the class loader chain was recognized, so we
     // return true.
     return true;
@@ -2686,6 +2711,10 @@
         FindClassInBaseDexClassLoaderClassPath(soa, descriptor, hash, class_loader, result),
         *result,
         self);
+    RETURN_IF_UNRECOGNIZED_OR_FOUND_OR_EXCEPTION(
+        FindClassInSharedLibrariesAfter(soa, self, descriptor, hash, class_loader, result),
+        *result,
+        self);
 
     // Create a handle as RegisterDexFile may allocate dex caches (and cause thread suspension).
     StackHandleScope<1> hs(self);
@@ -9839,7 +9868,8 @@
     const std::vector<const DexFile*>& dex_files,
     Handle<mirror::Class> loader_class,
     Handle<mirror::ClassLoader> parent_loader,
-    Handle<mirror::ObjectArray<mirror::ClassLoader>> shared_libraries) {
+    Handle<mirror::ObjectArray<mirror::ClassLoader>> shared_libraries,
+    Handle<mirror::ObjectArray<mirror::ClassLoader>> shared_libraries_after) {
 
   StackHandleScope<5> hs(self);
 
@@ -9959,6 +9989,12 @@
   DCHECK(shared_libraries_field != nullptr);
   shared_libraries_field->SetObject<false>(h_class_loader.Get(), shared_libraries.Get());
 
+  ArtField* shared_libraries_after_field =
+        jni::DecodeArtField(
+        WellKnownClasses::dalvik_system_BaseDexClassLoader_sharedLibraryLoadersAfter);
+  DCHECK(shared_libraries_after_field != nullptr);
+  shared_libraries_after_field->SetObject<false>(h_class_loader.Get(),
+                                                 shared_libraries_after.Get());
   return h_class_loader.Get();
 }
 
@@ -9966,7 +10002,8 @@
                                                 const std::vector<const DexFile*>& dex_files,
                                                 jclass loader_class,
                                                 jobject parent_loader,
-                                                jobject shared_libraries) {
+                                                jobject shared_libraries,
+                                                jobject shared_libraries_after) {
   CHECK(self->GetJniEnv()->IsSameObject(loader_class,
                                         WellKnownClasses::dalvik_system_PathClassLoader) ||
         self->GetJniEnv()->IsSameObject(loader_class,
@@ -9979,7 +10016,7 @@
   ScopedObjectAccessUnchecked soa(self);
 
   // For now, create a libcore-level DexFile for each ART DexFile. This "explodes" multidex.
-  StackHandleScope<4> hs(self);
+  StackHandleScope<5> hs(self);
 
   Handle<mirror::Class> h_loader_class =
       hs.NewHandle<mirror::Class>(soa.Decode<mirror::Class>(loader_class));
@@ -9987,13 +10024,16 @@
       hs.NewHandle<mirror::ClassLoader>(soa.Decode<mirror::ClassLoader>(parent_loader));
   Handle<mirror::ObjectArray<mirror::ClassLoader>> h_shared_libraries =
       hs.NewHandle(soa.Decode<mirror::ObjectArray<mirror::ClassLoader>>(shared_libraries));
+  Handle<mirror::ObjectArray<mirror::ClassLoader>> h_shared_libraries_after =
+        hs.NewHandle(soa.Decode<mirror::ObjectArray<mirror::ClassLoader>>(shared_libraries_after));
 
   ObjPtr<mirror::ClassLoader> loader = CreateWellKnownClassLoader(
       self,
       dex_files,
       h_loader_class,
       h_parent,
-      h_shared_libraries);
+      h_shared_libraries,
+      h_shared_libraries_after);
 
   // Make it a global ref and return.
   ScopedLocalRef<jobject> local_ref(
diff --git a/runtime/class_linker.h b/runtime/class_linker.h
index 8f33405..eaaf128 100644
--- a/runtime/class_linker.h
+++ b/runtime/class_linker.h
@@ -665,7 +665,8 @@
                                      const std::vector<const DexFile*>& dex_files,
                                      jclass loader_class,
                                      jobject parent_loader,
-                                     jobject shared_libraries = nullptr)
+                                     jobject shared_libraries = nullptr,
+                                     jobject shared_libraries_after = nullptr)
       REQUIRES_SHARED(Locks::mutator_lock_)
       REQUIRES(!Locks::dex_lock_);
 
@@ -683,7 +684,8 @@
       const std::vector<const DexFile*>& dex_files,
       Handle<mirror::Class> loader_class,
       Handle<mirror::ClassLoader> parent_loader,
-      Handle<mirror::ObjectArray<mirror::ClassLoader>> shared_libraries)
+      Handle<mirror::ObjectArray<mirror::ClassLoader>> shared_libraries,
+      Handle<mirror::ObjectArray<mirror::ClassLoader>> shared_libraries_after)
           REQUIRES_SHARED(Locks::mutator_lock_)
           REQUIRES(!Locks::dex_lock_);
 
@@ -1015,6 +1017,25 @@
       REQUIRES_SHARED(Locks::mutator_lock_)
       REQUIRES(!Locks::dex_lock_);
 
+  bool FindClassInSharedLibrariesHelper(ScopedObjectAccessAlreadyRunnable& soa,
+                                        Thread* self,
+                                        const char* descriptor,
+                                        size_t hash,
+                                        Handle<mirror::ClassLoader> class_loader,
+                                        ArtField* field,
+                                        /*out*/ ObjPtr<mirror::Class>* result)
+      REQUIRES_SHARED(Locks::mutator_lock_)
+      REQUIRES(!Locks::dex_lock_);
+
+  bool FindClassInSharedLibrariesAfter(ScopedObjectAccessAlreadyRunnable& soa,
+                                       Thread* self,
+                                       const char* descriptor,
+                                       size_t hash,
+                                       Handle<mirror::ClassLoader> class_loader,
+                                       /*out*/ ObjPtr<mirror::Class>* result)
+      REQUIRES_SHARED(Locks::mutator_lock_)
+      REQUIRES(!Locks::dex_lock_);
+
   // Finds the class in the classpath of the given class loader. It only searches the class loader
   // dex files and does not recurse into its parent.
   // The method checks that the provided class loader is either a PathClassLoader or a
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;
diff --git a/runtime/class_loader_context.h b/runtime/class_loader_context.h
index 33af16a..eceea00 100644
--- a/runtime/class_loader_context.h
+++ b/runtime/class_loader_context.h
@@ -225,6 +225,8 @@
     ClassLoaderType type;
     // Shared libraries this context has.
     std::vector<std::unique_ptr<ClassLoaderInfo>> shared_libraries;
+    // Shared libraries that will be loaded after apks code that this context has.
+    std::vector<std::unique_ptr<ClassLoaderInfo>> shared_libraries_after;
     // The list of class path elements that this loader loads.
     // Note that this list may contain relative paths.
     std::vector<std::string> classpath;
@@ -297,7 +299,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_);
 
   // Encodes the context as a string suitable to be passed to dex2oat or to be added to the
diff --git a/runtime/class_loader_context_test.cc b/runtime/class_loader_context_test.cc
index bf51ae3..073b4b6 100644
--- a/runtime/class_loader_context_test.cc
+++ b/runtime/class_loader_context_test.cc
@@ -77,6 +77,15 @@
         classpath);
   }
 
+  void VerifyClassLoaderSharedLibraryPCLAfter(ClassLoaderContext* context,
+                                              size_t loader_index,
+                                              size_t shared_library_index,
+                                              const std::string& classpath) {
+    VerifyClassLoaderInfoSLAfter(
+        context, loader_index, shared_library_index, ClassLoaderContext::kPathClassLoader,
+        classpath);
+  }
+
   void VerifyClassLoaderSharedLibraryIMC(ClassLoaderContext* context,
                                          size_t loader_index,
                                          size_t shared_library_index,
@@ -356,7 +365,25 @@
     ASSERT_GT(info.shared_libraries.size(), shared_library_index);
     const ClassLoaderContext::ClassLoaderInfo& sl =
         *info.shared_libraries[shared_library_index].get();
-    ASSERT_EQ(type, info.type);
+    ASSERT_EQ(type, sl.type);
+    std::vector<std::string> expected_classpath;
+    Split(classpath, ':', &expected_classpath);
+    ASSERT_EQ(expected_classpath, sl.classpath);
+  }
+
+  void VerifyClassLoaderInfoSLAfter(ClassLoaderContext* context,
+                               size_t loader_index,
+                               size_t shared_library_index,
+                               ClassLoaderContext::ClassLoaderType type,
+                               const std::string& classpath) {
+    ASSERT_TRUE(context != nullptr);
+    ASSERT_GT(context->GetParentChainSize(), loader_index);
+    const ClassLoaderContext::ClassLoaderInfo& info = *context->GetParent(loader_index);
+    ASSERT_GT(info.shared_libraries_after.size(), shared_library_index);
+
+    const ClassLoaderContext::ClassLoaderInfo& sl =
+        *info.shared_libraries_after[shared_library_index].get();
+    ASSERT_EQ(type, sl.type);
     std::vector<std::string> expected_classpath;
     Split(classpath, ':', &expected_classpath);
     ASSERT_EQ(expected_classpath, sl.classpath);
@@ -437,10 +464,13 @@
 
 TEST_F(ClassLoaderContextTest, ParseSharedLibraries) {
   std::unique_ptr<ClassLoaderContext> context = ClassLoaderContext::Create(
-      "PCL[a.dex:b.dex]{PCL[s1.dex]#PCL[s2.dex:s3.dex]};DLC[c.dex:d.dex]{DLC[s4.dex]}");
+      "PCL[a.dex:b.dex]{PCL[s1.dex]#PCL[s2.dex:s3.dex]#~PCL[s5.dex]#~PCL[s6.dex:s7.dex]};"
+      "DLC[c.dex:d.dex]{DLC[s4.dex]}");
   VerifyContextSize(context.get(), 2);
   VerifyClassLoaderSharedLibraryPCL(context.get(), 0, 0, "s1.dex");
   VerifyClassLoaderSharedLibraryPCL(context.get(), 0, 1, "s2.dex:s3.dex");
+  VerifyClassLoaderSharedLibraryPCLAfter(context.get(), 0, 0, "s5.dex");
+  VerifyClassLoaderSharedLibraryPCLAfter(context.get(), 0, 1, "s6.dex:s7.dex");
   VerifyClassLoaderDLC(context.get(), 1, "c.dex:d.dex");
   VerifyClassLoaderSharedLibraryDLC(context.get(), 1, 0, "s4.dex");
 }
diff --git a/runtime/common_runtime_test.cc b/runtime/common_runtime_test.cc
index b748e37..4eb3408 100644
--- a/runtime/common_runtime_test.cc
+++ b/runtime/common_runtime_test.cc
@@ -255,7 +255,8 @@
 CommonRuntimeTestImpl::LoadDexInWellKnownClassLoader(const std::vector<std::string>& dex_names,
                                                      jclass loader_class,
                                                      jobject parent_loader,
-                                                     jobject shared_libraries) {
+                                                     jobject shared_libraries,
+                                                     jobject shared_libraries_after) {
   std::vector<const DexFile*> class_path;
   for (const std::string& dex_name : dex_names) {
     std::vector<std::unique_ptr<const DexFile>> dex_files = OpenTestDexFiles(dex_name.c_str());
@@ -273,7 +274,8 @@
       class_path,
       loader_class,
       parent_loader,
-      shared_libraries);
+      shared_libraries,
+      shared_libraries_after);
 
   {
     // Verify we build the correct chain.
@@ -301,19 +303,23 @@
 
 jobject CommonRuntimeTestImpl::LoadDexInPathClassLoader(const std::string& dex_name,
                                                         jobject parent_loader,
-                                                        jobject shared_libraries) {
+                                                        jobject shared_libraries,
+                                                        jobject shared_libraries_after) {
   return LoadDexInPathClassLoader(std::vector<std::string>{ dex_name },
                                   parent_loader,
-                                  shared_libraries);
+                                  shared_libraries,
+                                  shared_libraries_after);
 }
 
 jobject CommonRuntimeTestImpl::LoadDexInPathClassLoader(const std::vector<std::string>& names,
                                                         jobject parent_loader,
-                                                        jobject shared_libraries) {
+                                                        jobject shared_libraries,
+                                                        jobject shared_libraries_after) {
   return LoadDexInWellKnownClassLoader(names,
                                        WellKnownClasses::dalvik_system_PathClassLoader,
                                        parent_loader,
-                                       shared_libraries);
+                                       shared_libraries,
+                                       shared_libraries_after);
 }
 
 jobject CommonRuntimeTestImpl::LoadDexInDelegateLastClassLoader(const std::string& dex_name,
diff --git a/runtime/common_runtime_test.h b/runtime/common_runtime_test.h
index d3995f0..7c11fd8 100644
--- a/runtime/common_runtime_test.h
+++ b/runtime/common_runtime_test.h
@@ -154,16 +154,19 @@
 
   jobject LoadDexInPathClassLoader(const std::string& dex_name,
                                    jobject parent_loader,
-                                   jobject shared_libraries = nullptr);
+                                   jobject shared_libraries = nullptr,
+                                   jobject shared_libraries_after = nullptr);
   jobject LoadDexInPathClassLoader(const std::vector<std::string>& dex_names,
                                    jobject parent_loader,
-                                   jobject shared_libraries = nullptr);
+                                   jobject shared_libraries = nullptr,
+                                   jobject shared_libraries_after = nullptr);
   jobject LoadDexInDelegateLastClassLoader(const std::string& dex_name, jobject parent_loader);
   jobject LoadDexInInMemoryDexClassLoader(const std::string& dex_name, jobject parent_loader);
   jobject LoadDexInWellKnownClassLoader(const std::vector<std::string>& dex_names,
                                         jclass loader_class,
                                         jobject parent_loader,
-                                        jobject shared_libraries = nullptr);
+                                        jobject shared_libraries = nullptr,
+                                        jobject shared_libraries_after = nullptr);
 
   void VisitDexes(ArrayRef<const std::string> dexes,
                   const std::function<void(MethodReference)>& method_visitor,
diff --git a/runtime/hidden_api_test.cc b/runtime/hidden_api_test.cc
index 7cec10c..f5cd15e 100644
--- a/runtime/hidden_api_test.cc
+++ b/runtime/hidden_api_test.cc
@@ -82,7 +82,8 @@
       MakeNonOwningPointerVector(*dex_files),
       h_class,
       /* parent_loader= */ ScopedNullHandle<mirror::ClassLoader>(),
-      /* shared_libraries= */ ScopedNullHandle<mirror::ObjectArray<mirror::ClassLoader>>()));
+      /* shared_libraries= */ ScopedNullHandle<mirror::ObjectArray<mirror::ClassLoader>>(),
+      /* shared_libraries_after= */ ScopedNullHandle<mirror::ObjectArray<mirror::ClassLoader>>()));
   for (const auto& dex_file : *dex_files) {
     linker->RegisterDexFile(*dex_file.get(), h_loader.Get());
   }
diff --git a/runtime/well_known_classes.cc b/runtime/well_known_classes.cc
index 8414aa4..645f3ad 100644
--- a/runtime/well_known_classes.cc
+++ b/runtime/well_known_classes.cc
@@ -132,6 +132,7 @@
 jfieldID WellKnownClasses::dalvik_system_DexFile_fileName;
 jfieldID WellKnownClasses::dalvik_system_BaseDexClassLoader_pathList;
 jfieldID WellKnownClasses::dalvik_system_BaseDexClassLoader_sharedLibraryLoaders;
+jfieldID WellKnownClasses::dalvik_system_BaseDexClassLoader_sharedLibraryLoadersAfter;
 jfieldID WellKnownClasses::dalvik_system_DexPathList_dexElements;
 jfieldID WellKnownClasses::dalvik_system_DexPathList__Element_dexFile;
 jfieldID WellKnownClasses::dalvik_system_VMRuntime_nonSdkApiUsageConsumer;
@@ -421,6 +422,7 @@
 
   dalvik_system_BaseDexClassLoader_pathList = CacheField(env, dalvik_system_BaseDexClassLoader, false, "pathList", "Ldalvik/system/DexPathList;");
   dalvik_system_BaseDexClassLoader_sharedLibraryLoaders = CacheField(env, dalvik_system_BaseDexClassLoader, false, "sharedLibraryLoaders", "[Ljava/lang/ClassLoader;");
+  dalvik_system_BaseDexClassLoader_sharedLibraryLoadersAfter = CacheField(env, dalvik_system_BaseDexClassLoader, false, "sharedLibraryLoadersAfter", "[Ljava/lang/ClassLoader;");
   dalvik_system_DexFile_cookie = CacheField(env, dalvik_system_DexFile, false, "mCookie", "Ljava/lang/Object;");
   dalvik_system_DexFile_fileName = CacheField(env, dalvik_system_DexFile, false, "mFileName", "Ljava/lang/String;");
   dalvik_system_DexPathList_dexElements = CacheField(env, dalvik_system_DexPathList, false, "dexElements", "[Ldalvik/system/DexPathList$Element;");
diff --git a/runtime/well_known_classes.h b/runtime/well_known_classes.h
index 434d041..7da085f 100644
--- a/runtime/well_known_classes.h
+++ b/runtime/well_known_classes.h
@@ -143,6 +143,7 @@
 
   static jfieldID dalvik_system_BaseDexClassLoader_pathList;
   static jfieldID dalvik_system_BaseDexClassLoader_sharedLibraryLoaders;
+  static jfieldID dalvik_system_BaseDexClassLoader_sharedLibraryLoadersAfter;
   static jfieldID dalvik_system_DexFile_cookie;
   static jfieldID dalvik_system_DexFile_fileName;
   static jfieldID dalvik_system_DexPathList_dexElements;