Merge "Start using shared libraries class loader."
am: e7753e084f

Change-Id: I927599cc923e61d73d03c3ec9b469529f42f3225
diff --git a/core/java/android/app/ApplicationLoaders.java b/core/java/android/app/ApplicationLoaders.java
index 30d6bee..9ef24c6 100644
--- a/core/java/android/app/ApplicationLoaders.java
+++ b/core/java/android/app/ApplicationLoaders.java
@@ -27,6 +27,7 @@
 import dalvik.system.PathClassLoader;
 
 import java.util.Collection;
+import java.util.List;
 
 /** @hide */
 public class ApplicationLoaders {
@@ -38,15 +39,25 @@
     ClassLoader getClassLoader(String zip, int targetSdkVersion, boolean isBundled,
                                String librarySearchPath, String libraryPermittedPath,
                                ClassLoader parent, String classLoaderName) {
+        return getClassLoaderWithSharedLibraries(zip, targetSdkVersion, isBundled,
+                              librarySearchPath, libraryPermittedPath, parent, classLoaderName,
+                              null);
+    }
+
+    ClassLoader getClassLoaderWithSharedLibraries(
+            String zip, int targetSdkVersion, boolean isBundled,
+            String librarySearchPath, String libraryPermittedPath,
+            ClassLoader parent, String classLoaderName,
+            List<ClassLoader> sharedLibraries) {
         // For normal usage the cache key used is the same as the zip path.
         return getClassLoader(zip, targetSdkVersion, isBundled, librarySearchPath,
-                              libraryPermittedPath, parent, zip, classLoaderName);
+                              libraryPermittedPath, parent, zip, classLoaderName, sharedLibraries);
     }
 
     private ClassLoader getClassLoader(String zip, int targetSdkVersion, boolean isBundled,
                                        String librarySearchPath, String libraryPermittedPath,
                                        ClassLoader parent, String cacheKey,
-                                       String classLoaderName) {
+                                       String classLoaderName, List<ClassLoader> sharedLibraries) {
         /*
          * This is the parent we use if they pass "null" in.  In theory
          * this should be the "system" class loader; in practice we
@@ -75,7 +86,7 @@
 
                 ClassLoader classloader = ClassLoaderFactory.createClassLoader(
                         zip,  librarySearchPath, libraryPermittedPath, parent,
-                        targetSdkVersion, isBundled, classLoaderName);
+                        targetSdkVersion, isBundled, classLoaderName, sharedLibraries);
 
                 Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
 
@@ -90,7 +101,7 @@
 
             Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, zip);
             ClassLoader loader = ClassLoaderFactory.createClassLoader(
-                    zip, null, parent, classLoaderName);
+                    zip, null, parent, classLoaderName, sharedLibraries);
             Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
             return loader;
         }
@@ -110,7 +121,7 @@
         // The cache key is passed separately to enable the stub WebView to be cached under the
         // stub's APK path, when the actual package path is the donor APK.
         return getClassLoader(packagePath, Build.VERSION.SDK_INT, false, libsPath, null, null,
-                              cacheKey, null /* classLoaderName */);
+                              cacheKey, null /* classLoaderName */, null /* sharedLibraries */);
     }
 
     /**
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index da4f77b..3f10754 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -29,6 +29,7 @@
 import android.content.pm.IPackageManager;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.SharedLibraryInfo;
 import android.content.pm.dex.ArtManager;
 import android.content.pm.split.SplitDependencyLoader;
 import android.content.res.AssetManager;
@@ -70,8 +71,10 @@
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.Enumeration;
+import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Objects;
+import java.util.Set;
 
 final class IntentReceiverLeaked extends AndroidRuntimeException {
     @UnsupportedAppUsage
@@ -397,6 +400,24 @@
         makePaths(activityThread, false, aInfo, outZipPaths, null);
     }
 
+    private static void appendSharedLibrariesLibPathsIfNeeded(
+            List<SharedLibraryInfo> sharedLibraries, ApplicationInfo aInfo,
+            Set<String> outSeenPaths,
+            List<String> outLibPaths) {
+        if (sharedLibraries == null) {
+            return;
+        }
+        for (SharedLibraryInfo lib : sharedLibraries) {
+            List<String> paths = lib.getAllCodePaths();
+            outSeenPaths.addAll(paths);
+            for (String path : paths) {
+                appendApkLibPathIfNeeded(path, aInfo, outLibPaths);
+            }
+            appendSharedLibrariesLibPathsIfNeeded(
+                    lib.getDependencies(), aInfo, outSeenPaths, outLibPaths);
+        }
+    }
+
     public static void makePaths(ActivityThread activityThread,
                                  boolean isBundledApp,
                                  ApplicationInfo aInfo,
@@ -404,7 +425,6 @@
                                  List<String> outLibPaths) {
         final String appDir = aInfo.sourceDir;
         final String libDir = aInfo.nativeLibraryDir;
-        final String[] sharedLibraries = aInfo.sharedLibraryFiles;
 
         outZipPaths.clear();
         outZipPaths.add(appDir);
@@ -499,11 +519,19 @@
             }
         }
 
-        // Prepend the shared libraries, maintaining their original order where possible.
-        if (sharedLibraries != null) {
+        // Add the shared libraries native paths. The dex files in shared libraries will
+        // be resolved through shared library loaders, which are setup later.
+        Set<String> outSeenPaths = new LinkedHashSet<>();
+        appendSharedLibrariesLibPathsIfNeeded(
+                aInfo.sharedLibraryInfos, aInfo, outSeenPaths, outLibPaths);
+
+        // ApplicationInfo.sharedLibraryFiles is a public API, so anyone can change it.
+        // We prepend shared libraries that the package manager hasn't seen, maintaining their
+        // original order where possible.
+        if (aInfo.sharedLibraryFiles != null) {
             int index = 0;
-            for (String lib : sharedLibraries) {
-                if (!outZipPaths.contains(lib)) {
+            for (String lib : aInfo.sharedLibraryFiles) {
+                if (!outSeenPaths.contains(lib) && !outZipPaths.contains(lib)) {
                     outZipPaths.add(index, lib);
                     index++;
                     appendApkLibPathIfNeeded(lib, aInfo, outLibPaths);
@@ -631,6 +659,43 @@
         return mSplitLoader.getSplitPathsForSplit(splitName);
     }
 
+    /**
+     * Create a class loader for the {@code sharedLibrary}. Shared libraries are canonicalized,
+     * so if we already created a class loader with that shared library, we return it.
+     *
+     * Implementation notes: the canonicalization of shared libraries is something dex2oat
+     * also does.
+     */
+    ClassLoader createSharedLibraryLoader(SharedLibraryInfo sharedLibrary,
+            boolean isBundledApp, String librarySearchPath, String libraryPermittedPath) {
+        List<String> paths = sharedLibrary.getAllCodePaths();
+        List<ClassLoader> sharedLibraries = createSharedLibrariesLoaders(
+                sharedLibrary.getDependencies(), isBundledApp, librarySearchPath,
+                libraryPermittedPath);
+        final String jars = (paths.size() == 1) ? paths.get(0) :
+                TextUtils.join(File.pathSeparator, paths);
+
+        // Shared libraries get a null parent: this has the side effect of having canonicalized
+        // shared libraries using ApplicationLoaders cache, which is the behavior we want.
+        return ApplicationLoaders.getDefault().getClassLoaderWithSharedLibraries(jars,
+                    mApplicationInfo.targetSdkVersion, isBundledApp, librarySearchPath,
+                    libraryPermittedPath, /* parent */ null,
+                    /* classLoaderName */ null, sharedLibraries);
+    }
+
+    private List<ClassLoader> createSharedLibrariesLoaders(List<SharedLibraryInfo> sharedLibraries,
+            boolean isBundledApp, String librarySearchPath, String libraryPermittedPath) {
+        if (sharedLibraries == null) {
+            return null;
+        }
+        List<ClassLoader> loaders = new ArrayList<>();
+        for (SharedLibraryInfo info : sharedLibraries) {
+            loaders.add(createSharedLibraryLoader(
+                    info, isBundledApp, librarySearchPath, libraryPermittedPath));
+        }
+        return loaders;
+    }
+
     private void createOrUpdateClassLoaderLocked(List<String> addedPaths) {
         if (mPackageName.equals("android")) {
             // Note: This branch is taken for system server and we don't need to setup
@@ -759,10 +824,14 @@
             // as this is early and necessary.
             StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
 
-            mDefaultClassLoader = ApplicationLoaders.getDefault().getClassLoader(zip,
-                    mApplicationInfo.targetSdkVersion, isBundledApp, librarySearchPath,
+            List<ClassLoader> sharedLibraries = createSharedLibrariesLoaders(
+                    mApplicationInfo.sharedLibraryInfos, isBundledApp, librarySearchPath,
+                    libraryPermittedPath);
+
+            mDefaultClassLoader = ApplicationLoaders.getDefault().getClassLoaderWithSharedLibraries(
+                    zip, mApplicationInfo.targetSdkVersion, isBundledApp, librarySearchPath,
                     libraryPermittedPath, mBaseClassLoader,
-                    mApplicationInfo.classLoaderName);
+                    mApplicationInfo.classLoaderName, sharedLibraries);
             mAppComponentFactory = createAppFactory(mApplicationInfo, mDefaultClassLoader);
 
             StrictMode.setThreadPolicy(oldPolicy);
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index 0ec509e..a74e4d7 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -45,6 +45,7 @@
 import java.text.Collator;
 import java.util.Arrays;
 import java.util.Comparator;
+import java.util.List;
 import java.util.Objects;
 import java.util.UUID;
 
@@ -814,7 +815,17 @@
      * the structure.
      */
     public String[] sharedLibraryFiles;
-    
+
+    /**
+     * List of all shared libraries this application is linked against.  This
+     * field is only set if the {@link PackageManager#GET_SHARED_LIBRARY_FILES
+     * PackageManager.GET_SHARED_LIBRARY_FILES} flag was used when retrieving
+     * the structure.
+     *
+     * {@hide}
+     */
+    public List<SharedLibraryInfo> sharedLibraryInfos;
+
     /**
      * Full path to the default directory assigned to the package for its
      * persistent data.
@@ -1458,6 +1469,7 @@
         seInfo = orig.seInfo;
         seInfoUser = orig.seInfoUser;
         sharedLibraryFiles = orig.sharedLibraryFiles;
+        sharedLibraryInfos = orig.sharedLibraryInfos;
         dataDir = orig.dataDir;
         deviceProtectedDataDir = orig.deviceProtectedDataDir;
         credentialProtectedDataDir = orig.credentialProtectedDataDir;
@@ -1533,6 +1545,7 @@
         dest.writeString(seInfo);
         dest.writeString(seInfoUser);
         dest.writeStringArray(sharedLibraryFiles);
+        dest.writeTypedList(sharedLibraryInfos);
         dest.writeString(dataDir);
         dest.writeString(deviceProtectedDataDir);
         dest.writeString(credentialProtectedDataDir);
@@ -1605,6 +1618,7 @@
         seInfo = source.readString();
         seInfoUser = source.readString();
         sharedLibraryFiles = source.readStringArray();
+        sharedLibraryInfos = source.createTypedArrayList(SharedLibraryInfo.CREATOR);
         dataDir = source.readString();
         deviceProtectedDataDir = source.readString();
         credentialProtectedDataDir = source.readString();
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 7aea261..ecb9dbf 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -7555,6 +7555,7 @@
         }
         if ((flags & PackageManager.GET_SHARED_LIBRARY_FILES) != 0) {
             ai.sharedLibraryFiles = p.usesLibraryFiles;
+            ai.sharedLibraryInfos = p.usesLibraryInfos;
         }
         if (state.stopped) {
             ai.flags |= ApplicationInfo.FLAG_STOPPED;
diff --git a/core/java/android/content/pm/SharedLibraryInfo.java b/core/java/android/content/pm/SharedLibraryInfo.java
index 096301c..ad82626d 100644
--- a/core/java/android/content/pm/SharedLibraryInfo.java
+++ b/core/java/android/content/pm/SharedLibraryInfo.java
@@ -74,6 +74,7 @@
     private final String mPath;
     private final String mPackageName;
     private final String mName;
+    private final List<String> mCodePaths;
 
     private final long mVersion;
     private final @Type int mType;
@@ -84,6 +85,8 @@
     /**
      * Creates a new instance.
      *
+     * @param codePaths For a non {@link #TYPE_BUILTIN builtin} library, the locations of jars of
+     *                  this shared library. Null for builtin library.
      * @param name The lib name.
      * @param version The lib version if not builtin.
      * @param type The lib type.
@@ -92,11 +95,13 @@
      *
      * @hide
      */
-    public SharedLibraryInfo(String path, String packageName, String name, long version, int type,
+    public SharedLibraryInfo(String path, String packageName, List<String> codePaths,
+            String name, long version, int type,
             VersionedPackage declaringPackage, List<VersionedPackage> dependentPackages,
             List<SharedLibraryInfo> dependencies) {
         mPath = path;
         mPackageName = packageName;
+        mCodePaths = codePaths;
         mName = name;
         mVersion = version;
         mType = type;
@@ -106,7 +111,8 @@
     }
 
     private SharedLibraryInfo(Parcel parcel) {
-        this(parcel.readString(), parcel.readString(), parcel.readString(), parcel.readLong(),
+        this(parcel.readString(), parcel.readString(), parcel.readArrayList(null),
+                parcel.readString(), parcel.readLong(),
                 parcel.readInt(), parcel.readParcelable(null), parcel.readArrayList(null),
                 parcel.createTypedArrayList(SharedLibraryInfo.CREATOR));
     }
@@ -155,6 +161,25 @@
     }
 
     /**
+     * Get all code paths for that library.
+     *
+     * @return All code paths.
+     *
+     * @hide
+     */
+    public List<String> getAllCodePaths() {
+        if (getPath() != null) {
+            // Builtin library.
+            ArrayList<String> list = new ArrayList<>();
+            list.add(getPath());
+            return list;
+        } else {
+            // Static or dynamic library.
+            return mCodePaths;
+        }
+    }
+
+    /**
      * Add a library dependency to that library. Note that this
      * should be called under the package manager lock.
      *
@@ -273,6 +298,7 @@
     public void writeToParcel(Parcel parcel, int flags) {
         parcel.writeString(mPath);
         parcel.writeString(mPackageName);
+        parcel.writeList(mCodePaths);
         parcel.writeString(mName);
         parcel.writeLong(mVersion);
         parcel.writeInt(mType);
diff --git a/core/java/com/android/internal/os/ClassLoaderFactory.java b/core/java/com/android/internal/os/ClassLoaderFactory.java
index 387857f..c5bc45a 100644
--- a/core/java/com/android/internal/os/ClassLoaderFactory.java
+++ b/core/java/com/android/internal/os/ClassLoaderFactory.java
@@ -22,6 +22,8 @@
 import dalvik.system.DexClassLoader;
 import dalvik.system.PathClassLoader;
 
+import java.util.List;
+
 /**
  * Creates class loaders.
  *
@@ -37,6 +39,13 @@
             DelegateLastClassLoader.class.getName();
 
     /**
+     * Returns the name of the class for PathClassLoader.
+     */
+    public static String getPathClassLoaderName() {
+        return PATH_CLASS_LOADER_NAME;
+    }
+
+    /**
      * Returns true if {@code name} is a supported classloader. {@code name} must be a
      * binary name of a class, as defined by {@code Class.getName}.
      */
@@ -68,25 +77,43 @@
      * is created.
      */
     public static ClassLoader createClassLoader(String dexPath,
-            String librarySearchPath, ClassLoader parent, String classloaderName) {
+            String librarySearchPath, ClassLoader parent, String classloaderName,
+            List<ClassLoader> sharedLibraries) {
+        ClassLoader[] arrayOfSharedLibraries = (sharedLibraries == null)
+                ? null
+                : sharedLibraries.toArray(new ClassLoader[sharedLibraries.size()]);
         if (isPathClassLoaderName(classloaderName)) {
-            return new PathClassLoader(dexPath, librarySearchPath, parent);
+            return new PathClassLoader(dexPath, librarySearchPath, parent, arrayOfSharedLibraries);
         } else if (isDelegateLastClassLoaderName(classloaderName)) {
-            return new DelegateLastClassLoader(dexPath, librarySearchPath, parent);
+            return new DelegateLastClassLoader(dexPath, librarySearchPath, parent,
+                    arrayOfSharedLibraries);
         }
 
         throw new AssertionError("Invalid classLoaderName: " + classloaderName);
     }
 
     /**
+     * Same as {@code createClassLoader} below, but passes a null list of shared
+     * libraries.
+     */
+    public static ClassLoader createClassLoader(String dexPath,
+            String librarySearchPath, String libraryPermittedPath, ClassLoader parent,
+            int targetSdkVersion, boolean isNamespaceShared, String classLoaderName) {
+        return createClassLoader(dexPath, librarySearchPath, libraryPermittedPath,
+            parent, targetSdkVersion, isNamespaceShared, classLoaderName, null);
+    }
+
+
+    /**
      * Create a ClassLoader and initialize a linker-namespace for it.
      */
     public static ClassLoader createClassLoader(String dexPath,
             String librarySearchPath, String libraryPermittedPath, ClassLoader parent,
-            int targetSdkVersion, boolean isNamespaceShared, String classloaderName) {
+            int targetSdkVersion, boolean isNamespaceShared, String classLoaderName,
+            List<ClassLoader> sharedLibraries) {
 
         final ClassLoader classLoader = createClassLoader(dexPath, librarySearchPath, parent,
-                classloaderName);
+                classLoaderName, sharedLibraries);
 
         boolean isForVendor = false;
         for (String path : dexPath.split(":")) {
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index bd51af2..af3bd6d 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -1418,6 +1418,7 @@
                     app = mPackageManager.getApplicationInfo(pkg.packageName,
                             PackageManager.GET_SHARED_LIBRARY_FILES);
                     pkg.applicationInfo.sharedLibraryFiles = app.sharedLibraryFiles;
+                    pkg.applicationInfo.sharedLibraryInfos = app.sharedLibraryInfos;
                 }
             } catch (NameNotFoundException e) {
                 packages.remove(a);
diff --git a/services/core/java/com/android/server/pm/OtaDexoptService.java b/services/core/java/com/android/server/pm/OtaDexoptService.java
index dea7863..41eaa24 100644
--- a/services/core/java/com/android/server/pm/OtaDexoptService.java
+++ b/services/core/java/com/android/server/pm/OtaDexoptService.java
@@ -333,9 +333,7 @@
         PackageDexOptimizer optimizer = new OTADexoptPackageDexOptimizer(
                 collectingInstaller, mPackageManagerService.mInstallLock, mContext);
 
-        String[] libraryDependencies = pkg.usesLibraryFiles;
-
-        optimizer.performDexOpt(pkg, libraryDependencies,
+        optimizer.performDexOpt(pkg, pkg.usesLibraryInfos,
                 null /* ISAs */,
                 null /* CompilerStats.PackageStats */,
                 mPackageManagerService.getDexManager().getPackageUseInfoOrDefault(pkg.packageName),
diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
index dc5213f..c197d23 100644
--- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java
+++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
@@ -20,6 +20,7 @@
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageParser;
+import android.content.pm.SharedLibraryInfo;
 import android.content.pm.dex.ArtManager;
 import android.content.pm.dex.DexMetadataHelper;
 import android.os.FileUtils;
@@ -128,7 +129,7 @@
      * <p>Calls to {@link com.android.server.pm.Installer#dexopt} on {@link #mInstaller} are
      * synchronized on {@link #mInstallLock}.
      */
-    int performDexOpt(PackageParser.Package pkg, String[] sharedLibraries,
+    int performDexOpt(PackageParser.Package pkg, List<SharedLibraryInfo> sharedLibraries,
             String[] instructionSets, CompilerStats.PackageStats packageStats,
             PackageDexUsage.PackageUseInfo packageUseInfo, DexoptOptions options) {
         if (pkg.applicationInfo.uid == -1) {
@@ -154,7 +155,8 @@
      * It assumes the install lock is held.
      */
     @GuardedBy("mInstallLock")
-    private int performDexOptLI(PackageParser.Package pkg, String[] sharedLibraries,
+    private int performDexOptLI(PackageParser.Package pkg,
+            List<SharedLibraryInfo> sharedLibraries,
             String[] targetInstructionSets, CompilerStats.PackageStats packageStats,
             PackageDexUsage.PackageUseInfo packageUseInfo, DexoptOptions options) {
         final String[] instructionSets = targetInstructionSets != null ?
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 2a605f5..47723da 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -2521,7 +2521,7 @@
             for (int i = 0; i < builtInLibCount; i++) {
                 String name = libConfig.keyAt(i);
                 String path = libConfig.valueAt(i);
-                addSharedLibraryLPw(path, null, name, SharedLibraryInfo.VERSION_UNDEFINED,
+                addSharedLibraryLPw(path, null, null, name, SharedLibraryInfo.VERSION_UNDEFINED,
                         SharedLibraryInfo.TYPE_BUILTIN, PLATFORM_PACKAGE_NAME, 0);
             }
             // Builtin libraries cannot encode their dependency where they are
@@ -5086,7 +5086,8 @@
                     }
 
                     SharedLibraryInfo resLibInfo = new SharedLibraryInfo(libInfo.getPath(),
-                            libInfo.getPackageName(), libInfo.getName(), libInfo.getLongVersion(),
+                            libInfo.getPackageName(), libInfo.getAllCodePaths(),
+                            libInfo.getName(), libInfo.getLongVersion(),
                             libInfo.getType(), libInfo.getDeclaringPackage(),
                             getPackagesUsingSharedLibraryLPr(libInfo, flags, userId),
                             (libInfo.getDependencies() == null
@@ -9386,7 +9387,7 @@
                     mDexManager.getPackageUseInfoOrDefault(depPackage.packageName), libraryOptions);
             }
         }
-        return pdo.performDexOpt(p, p.usesLibraryFiles, instructionSets,
+        return pdo.performDexOpt(p, p.usesLibraryInfos, instructionSets,
                 getOrCreateCompilerPackageStats(p),
                 mDexManager.getPackageUseInfoOrDefault(p.packageName), options);
     }
@@ -9756,7 +9757,6 @@
     @GuardedBy("mPackages")
     private void addSharedLibraryLPr(PackageParser.Package pkg, Set<String> usesLibraryFiles,
             SharedLibraryInfo libInfo, PackageParser.Package changingLib) {
-
         if (libInfo.getPath() != null) {
             usesLibraryFiles.add(libInfo.getPath());
             return;
@@ -11324,8 +11324,9 @@
         }
     }
 
-    private boolean addSharedLibraryLPw(String path, String apk, String name, long version,
-            int type, String declaringPackageName, long declaringVersionCode) {
+    private boolean addSharedLibraryLPw(String path, String apk, List<String> codePaths,
+            String name, long version, int type, String declaringPackageName,
+            long declaringVersionCode) {
         LongSparseArray<SharedLibraryInfo> versionedLib = mSharedLibraries.get(name);
         if (versionedLib == null) {
             versionedLib = new LongSparseArray<>();
@@ -11336,7 +11337,7 @@
         } else if (versionedLib.indexOfKey(version) >= 0) {
             return false;
         }
-        SharedLibraryInfo libraryInfo = new SharedLibraryInfo(path, apk, name,
+        SharedLibraryInfo libraryInfo = new SharedLibraryInfo(path, apk, codePaths, name,
                 version, type, new VersionedPackage(declaringPackageName, declaringVersionCode),
                 null, null);
         versionedLib.put(version, libraryInfo);
@@ -11423,10 +11424,17 @@
             if (pkg.staticSharedLibName != null) {
                 // Static shared libs don't allow renaming as they have synthetic package
                 // names to allow install of multiple versions, so use name from manifest.
-                if (addSharedLibraryLPw(null, pkg.packageName, pkg.staticSharedLibName,
+                if (addSharedLibraryLPw(null, pkg.packageName, pkg.getAllCodePaths(),
+                        pkg.staticSharedLibName,
                         pkg.staticSharedLibVersion, SharedLibraryInfo.TYPE_STATIC,
                         pkg.manifestPackageName, pkg.getLongVersionCode())) {
                     hasStaticSharedLibs = true;
+                    // Shared libraries for the package need to be updated.
+                    try {
+                        updateSharedLibrariesLPr(pkg, null);
+                    } catch (PackageManagerException e) {
+                        Slog.e(TAG, "updateSharedLibrariesLPr failed: ", e);
+                    }
                 } else {
                     Slog.w(TAG, "Package " + pkg.packageName + " library "
                                 + pkg.staticSharedLibName + " already exists; skipping");
@@ -11468,13 +11476,19 @@
                             allowed = true;
                         }
                         if (allowed) {
-                            if (!addSharedLibraryLPw(null, pkg.packageName, name,
-                                    SharedLibraryInfo.VERSION_UNDEFINED,
+                            if (!addSharedLibraryLPw(null, pkg.packageName, pkg.getAllCodePaths(),
+                                    name, SharedLibraryInfo.VERSION_UNDEFINED,
                                     SharedLibraryInfo.TYPE_DYNAMIC,
                                     pkg.packageName, pkg.getLongVersionCode())) {
                                 Slog.w(TAG, "Package " + pkg.packageName + " library "
                                         + name + " already exists; skipping");
                             }
+                            // Shared libraries for the package need to be updated.
+                            try {
+                                updateSharedLibrariesLPr(pkg, null);
+                            } catch (PackageManagerException e) {
+                                Slog.e(TAG, "updateSharedLibrariesLPr failed: ", e);
+                            }
                         } else {
                             Slog.w(TAG, "Package " + pkg.packageName + " declares lib "
                                     + name + " that is not declared on system image; skipping");
@@ -17711,7 +17725,7 @@
                     REASON_INSTALL,
                     DexoptOptions.DEXOPT_BOOT_COMPLETE |
                     DexoptOptions.DEXOPT_INSTALL_WITH_DEX_METADATA_FILE);
-            mPackageDexOptimizer.performDexOpt(pkg, pkg.usesLibraryFiles,
+            mPackageDexOptimizer.performDexOpt(pkg, pkg.usesLibraryInfos,
                     null /* instructionSets */,
                     getOrCreateCompilerPackageStats(pkg),
                     mDexManager.getPackageUseInfoOrDefault(pkg.packageName),
diff --git a/services/core/java/com/android/server/pm/dex/DexoptUtils.java b/services/core/java/com/android/server/pm/dex/DexoptUtils.java
index 9a12a2f..93ee44c 100644
--- a/services/core/java/com/android/server/pm/dex/DexoptUtils.java
+++ b/services/core/java/com/android/server/pm/dex/DexoptUtils.java
@@ -17,6 +17,7 @@
 package com.android.server.pm.dex;
 
 import android.content.pm.ApplicationInfo;
+import android.content.pm.SharedLibraryInfo;
 import android.util.Slog;
 import android.util.SparseArray;
 
@@ -29,6 +30,11 @@
 public final class DexoptUtils {
     private static final String TAG = "DexoptUtils";
 
+    // Shared libraries have more or less followed PCL behavior due to the way
+    // they were added to the classpath pre Q.
+    private static final String SHARED_LIBRARY_LOADER_TYPE =
+            ClassLoaderFactory.getPathClassLoaderName();
+
     private DexoptUtils() {}
 
     /**
@@ -62,12 +68,15 @@
      * android.app.ActivityThread, boolean, ApplicationInfo, List, List)}.
      */
     public static String[] getClassLoaderContexts(ApplicationInfo info,
-            String[] sharedLibraries, boolean[] pathsWithCode) {
+            List<SharedLibraryInfo> sharedLibraries, boolean[] pathsWithCode) {
         // The base class loader context contains only the shared library.
-        String sharedLibrariesClassPath = encodeClasspath(sharedLibraries);
-        String baseApkContextClassLoader = encodeClassLoader(
-                sharedLibrariesClassPath, info.classLoaderName);
+        String sharedLibrariesContext = "";
+        if (sharedLibraries != null) {
+            sharedLibrariesContext = encodeSharedLibraries(sharedLibraries);
+        }
 
+        String baseApkContextClassLoader = encodeClassLoader(
+                "", info.classLoaderName, sharedLibrariesContext);
         if (info.getSplitCodePaths() == null) {
             // The application has no splits.
             return new String[] {baseApkContextClassLoader};
@@ -81,11 +90,10 @@
         // The splits have an implicit dependency on the base apk.
         // This means that we have to add the base apk file in addition to the shared libraries.
         String baseApkName = new File(info.getBaseCodePath()).getName();
-        String sharedLibrariesAndBaseClassPath =
-                encodeClasspath(sharedLibrariesClassPath, baseApkName);
+        String baseClassPath = baseApkName;
 
         // The result is stored in classLoaderContexts.
-        // Index 0 is the class loaded context for the base apk.
+        // Index 0 is the class loader context for the base apk.
         // Index `i` is the class loader context encoding for split `i`.
         String[] classLoaderContexts = new String[/*base apk*/ 1 + splitRelativeCodePaths.length];
         classLoaderContexts[0] = pathsWithCode[0] ? baseApkContextClassLoader : null;
@@ -94,10 +102,14 @@
             // If the app didn't request for the splits to be loaded in isolation or if it does not
             // declare inter-split dependencies, then all the splits will be loaded in the base
             // apk class loader (in the order of their definition).
-            String classpath = sharedLibrariesAndBaseClassPath;
+            String classpath = baseClassPath;
             for (int i = 1; i < classLoaderContexts.length; i++) {
-                classLoaderContexts[i] = pathsWithCode[i]
-                        ? encodeClassLoader(classpath, info.classLoaderName) : null;
+                if (pathsWithCode[i]) {
+                    classLoaderContexts[i] = encodeClassLoader(
+                            classpath, info.classLoaderName, sharedLibrariesContext);
+                } else {
+                    classLoaderContexts[i] = null;
+                }
                 // Note that the splits with no code are not removed from the classpath computation.
                 // i.e. split_n might get the split_n-1 in its classpath dependency even
                 // if split_n-1 has no code.
@@ -124,7 +136,7 @@
                         info.splitClassLoaderNames[i]);
             }
             String splitDependencyOnBase = encodeClassLoader(
-                    sharedLibrariesAndBaseClassPath, info.classLoaderName);
+                    baseClassPath, info.classLoaderName);
             SparseArray<int[]> splitDependencies = info.splitDependencies;
 
             // Note that not all splits have dependencies (e.g. configuration splits)
@@ -149,7 +161,8 @@
                     // any dependency. In this case its context equals its declared class loader.
                     classLoaderContexts[i] = classLoaderContexts[i] == null
                             ? splitClassLoader
-                            : encodeClassLoaderChain(splitClassLoader, classLoaderContexts[i]);
+                            : encodeClassLoaderChain(splitClassLoader, classLoaderContexts[i])
+                                    + sharedLibrariesContext;
                 } else {
                     // This is a split without code, it has no dependency and it is not compiled.
                     // Its context will be null.
@@ -207,6 +220,31 @@
         return splitContext;
     }
 
+    private static String encodeSharedLibrary(SharedLibraryInfo sharedLibrary) {
+        List<String> paths = sharedLibrary.getAllCodePaths();
+        String classLoaderSpec = encodeClassLoader(
+                encodeClasspath(paths.toArray(new String[paths.size()])),
+                SHARED_LIBRARY_LOADER_TYPE);
+        if (sharedLibrary.getDependencies() != null) {
+            classLoaderSpec += encodeSharedLibraries(sharedLibrary.getDependencies());
+        }
+        return classLoaderSpec;
+    }
+
+    private static String encodeSharedLibraries(List<SharedLibraryInfo> sharedLibraries) {
+        String sharedLibrariesContext = "{";
+        boolean first = true;
+        for (SharedLibraryInfo info : sharedLibraries) {
+            if (!first) {
+                sharedLibrariesContext += "#";
+            }
+            first = false;
+            sharedLibrariesContext += encodeSharedLibrary(info);
+        }
+        sharedLibrariesContext += "}";
+        return sharedLibrariesContext;
+    }
+
     /**
      * Encodes the shared libraries classpathElements in a format accepted by dexopt.
      * NOTE: Keep this in sync with the dexopt expectations! Right now that is
@@ -258,6 +296,14 @@
     }
 
     /**
+     * Same as above, but appends {@param sharedLibraries} to the result.
+     */
+    private static String encodeClassLoader(String classpath, String classLoaderName,
+            String sharedLibraries) {
+        return encodeClassLoader(classpath, classLoaderName) + sharedLibraries;
+    }
+
+    /**
      * Links to dependencies together in a format accepted by dexopt.
      * For the special case when either of cl1 or cl2 equals
      * {@link PackageDexOptimizer#SKIP_SHARED_LIBRARY_CHECK}, the method returns the same. This
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
index cdbc665..69c0c0f 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
@@ -489,7 +489,8 @@
         pkg.usesLibraryFiles = new String[] { "foo13"};
 
         pkg.usesLibraryInfos = new ArrayList<>();
-        pkg.usesLibraryInfos.add(new SharedLibraryInfo(null, null, null, 0L, 0, null, null, null));
+        pkg.usesLibraryInfos.add(
+                new SharedLibraryInfo(null, null, null, null, 0L, 0, null, null, null));
 
         pkg.mOriginalPackages = new ArrayList<>();
         pkg.mOriginalPackages.add("foo14");
diff --git a/services/tests/servicestests/src/com/android/server/pm/dex/DexoptUtilsTest.java b/services/tests/servicestests/src/com/android/server/pm/dex/DexoptUtilsTest.java
index 6e0f56c..1542120 100644
--- a/services/tests/servicestests/src/com/android/server/pm/dex/DexoptUtilsTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/dex/DexoptUtilsTest.java
@@ -28,6 +28,7 @@
 import android.content.pm.ApplicationInfo;
 import android.support.test.filters.SmallTest;
 import android.support.test.runner.AndroidJUnit4;
+import android.content.pm.SharedLibraryInfo;
 import android.util.SparseArray;
 
 import dalvik.system.DelegateLastClassLoader;
@@ -39,6 +40,7 @@
 
 import java.io.File;
 import java.util.Arrays;
+import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 
@@ -108,22 +110,31 @@
         return data;
     }
 
+    private List<SharedLibraryInfo> createMockSharedLibrary(String [] sharedLibrary) {
+        SharedLibraryInfo info = new SharedLibraryInfo(null, null, Arrays.asList(sharedLibrary),
+                null, 0L, SharedLibraryInfo.TYPE_STATIC, null, null, null);
+        ArrayList<SharedLibraryInfo> libraries = new ArrayList<>();
+        libraries.add(info);
+        return libraries;
+    }
+
     @Test
     public void testSplitChain() {
         TestData data = createMockApplicationInfo(PATH_CLASS_LOADER_NAME, true, true);
-        String[] sharedLibrary = new String[] {"a.dex", "b.dex"};
+        List<SharedLibraryInfo> sharedLibrary =
+                createMockSharedLibrary(new String[] {"a.dex", "b.dex"});
         String[] contexts = DexoptUtils.getClassLoaderContexts(
                 data.info, sharedLibrary, data.pathsWithCode);
 
         assertEquals(9, contexts.length);
-        assertEquals("PCL[a.dex:b.dex]", contexts[0]);
-        assertEquals("DLC[];DLC[base-2.dex];PCL[base-4.dex];PCL[a.dex:b.dex:base.dex]",
+        assertEquals("PCL[]{PCL[a.dex:b.dex]}", contexts[0]);
+        assertEquals("DLC[];DLC[base-2.dex];PCL[base-4.dex];PCL[base.dex]{PCL[a.dex:b.dex]}",
                 contexts[1]);
-        assertEquals("DLC[];PCL[base-4.dex];PCL[a.dex:b.dex:base.dex]", contexts[2]);
-        assertEquals("PCL[];PCL[base-4.dex];PCL[a.dex:b.dex:base.dex]", contexts[3]);
-        assertEquals("PCL[];PCL[a.dex:b.dex:base.dex]", contexts[4]);
-        assertEquals("PCL[];PCL[a.dex:b.dex:base.dex]", contexts[5]);
-        assertEquals("PCL[];PCL[base-5.dex];PCL[a.dex:b.dex:base.dex]", contexts[6]);
+        assertEquals("DLC[];PCL[base-4.dex];PCL[base.dex]{PCL[a.dex:b.dex]}", contexts[2]);
+        assertEquals("PCL[];PCL[base-4.dex];PCL[base.dex]{PCL[a.dex:b.dex]}", contexts[3]);
+        assertEquals("PCL[];PCL[base.dex]{PCL[a.dex:b.dex]}", contexts[4]);
+        assertEquals("PCL[];PCL[base.dex]{PCL[a.dex:b.dex]}", contexts[5]);
+        assertEquals("PCL[];PCL[base-5.dex];PCL[base.dex]{PCL[a.dex:b.dex]}", contexts[6]);
         assertEquals(null, contexts[7]);  // config split
         assertEquals("PCL[]", contexts[8]);  // feature split with no dependency
     }
@@ -131,25 +142,28 @@
     @Test
     public void testSplitChainNoSplitDependencies() {
         TestData data = createMockApplicationInfo(PATH_CLASS_LOADER_NAME, true, false);
-        String[] sharedLibrary = new String[] {"a.dex", "b.dex"};
+        List<SharedLibraryInfo> sharedLibrary =
+                createMockSharedLibrary(new String[] {"a.dex", "b.dex"});
         String[] contexts = DexoptUtils.getClassLoaderContexts(
                 data.info, sharedLibrary, data.pathsWithCode);
 
         assertEquals(9, contexts.length);
-        assertEquals("PCL[a.dex:b.dex]", contexts[0]);
-        assertEquals("PCL[a.dex:b.dex:base.dex]", contexts[1]);
-        assertEquals("PCL[a.dex:b.dex:base.dex:base-1.dex]", contexts[2]);
-        assertEquals("PCL[a.dex:b.dex:base.dex:base-1.dex:base-2.dex]", contexts[3]);
-        assertEquals("PCL[a.dex:b.dex:base.dex:base-1.dex:base-2.dex:base-3.dex]", contexts[4]);
+        assertEquals("PCL[]{PCL[a.dex:b.dex]}", contexts[0]);
+        assertEquals("PCL[base.dex]{PCL[a.dex:b.dex]}", contexts[1]);
+        assertEquals("PCL[base.dex:base-1.dex]{PCL[a.dex:b.dex]}", contexts[2]);
+        assertEquals("PCL[base.dex:base-1.dex:base-2.dex]{PCL[a.dex:b.dex]}", contexts[3]);
         assertEquals(
-                "PCL[a.dex:b.dex:base.dex:base-1.dex:base-2.dex:base-3.dex:base-4.dex]",
+                "PCL[base.dex:base-1.dex:base-2.dex:base-3.dex]{PCL[a.dex:b.dex]}",
+                contexts[4]);
+        assertEquals(
+                "PCL[base.dex:base-1.dex:base-2.dex:base-3.dex:base-4.dex]{PCL[a.dex:b.dex]}",
                 contexts[5]);
         assertEquals(
-                "PCL[a.dex:b.dex:base.dex:base-1.dex:base-2.dex:base-3.dex:base-4.dex:base-5.dex]",
+                "PCL[base.dex:base-1.dex:base-2.dex:base-3.dex:base-4.dex:base-5.dex]{PCL[a.dex:b.dex]}",
                 contexts[6]);
         assertEquals(null, contexts[7]);  // config split
         assertEquals(
-                "PCL[a.dex:b.dex:base.dex:base-1.dex:base-2.dex:base-3.dex:base-4.dex:base-5.dex:base-6.dex:config-split-7.dex]",
+                "PCL[base.dex:base-1.dex:base-2.dex:base-3.dex:base-4.dex:base-5.dex:base-6.dex:config-split-7.dex]{PCL[a.dex:b.dex]}",
                 contexts[8]);  // feature split with no dependency
     }
 
@@ -200,18 +214,21 @@
     public void testSplitChainWithNullPrimaryClassLoader() {
         // A null classLoaderName should mean PathClassLoader.
         TestData data = createMockApplicationInfo(null, true, true);
-        String[] sharedLibrary = new String[] {"a.dex", "b.dex"};
+        List<SharedLibraryInfo> sharedLibrary =
+                createMockSharedLibrary(new String[] {"a.dex", "b.dex"});
         String[] contexts = DexoptUtils.getClassLoaderContexts(
                 data.info, sharedLibrary, data.pathsWithCode);
 
         assertEquals(9, contexts.length);
-        assertEquals("PCL[a.dex:b.dex]", contexts[0]);
-        assertEquals("DLC[];DLC[base-2.dex];PCL[base-4.dex];PCL[a.dex:b.dex:base.dex]", contexts[1]);
-        assertEquals("DLC[];PCL[base-4.dex];PCL[a.dex:b.dex:base.dex]", contexts[2]);
-        assertEquals("PCL[];PCL[base-4.dex];PCL[a.dex:b.dex:base.dex]", contexts[3]);
-        assertEquals("PCL[];PCL[a.dex:b.dex:base.dex]", contexts[4]);
-        assertEquals("PCL[];PCL[a.dex:b.dex:base.dex]", contexts[5]);
-        assertEquals("PCL[];PCL[base-5.dex];PCL[a.dex:b.dex:base.dex]", contexts[6]);
+        assertEquals("PCL[]{PCL[a.dex:b.dex]}", contexts[0]);
+        assertEquals(
+                "DLC[];DLC[base-2.dex];PCL[base-4.dex];PCL[base.dex]{PCL[a.dex:b.dex]}",
+                contexts[1]);
+        assertEquals("DLC[];PCL[base-4.dex];PCL[base.dex]{PCL[a.dex:b.dex]}", contexts[2]);
+        assertEquals("PCL[];PCL[base-4.dex];PCL[base.dex]{PCL[a.dex:b.dex]}", contexts[3]);
+        assertEquals("PCL[];PCL[base.dex]{PCL[a.dex:b.dex]}", contexts[4]);
+        assertEquals("PCL[];PCL[base.dex]{PCL[a.dex:b.dex]}", contexts[5]);
+        assertEquals("PCL[];PCL[base-5.dex];PCL[base.dex]{PCL[a.dex:b.dex]}", contexts[6]);
         assertEquals(null, contexts[7]);  // config split
         assertEquals("PCL[]", contexts[8]);  // feature split with no dependency
     }
@@ -219,35 +236,38 @@
     @Test
     public void tesNoSplits() {
         TestData data = createMockApplicationInfo(PATH_CLASS_LOADER_NAME, false, false);
-        String[] sharedLibrary = new String[] {"a.dex", "b.dex"};
+        List<SharedLibraryInfo> sharedLibrary =
+                createMockSharedLibrary(new String[] {"a.dex", "b.dex"});
         String[] contexts = DexoptUtils.getClassLoaderContexts(
                 data.info, sharedLibrary, data.pathsWithCode);
 
         assertEquals(1, contexts.length);
-        assertEquals("PCL[a.dex:b.dex]", contexts[0]);
+        assertEquals("PCL[]{PCL[a.dex:b.dex]}", contexts[0]);
     }
 
     @Test
     public void tesNoSplitsNullClassLoaderName() {
         TestData data = createMockApplicationInfo(null, false, false);
-        String[] sharedLibrary = new String[] {"a.dex", "b.dex"};
+        List<SharedLibraryInfo> sharedLibrary =
+                createMockSharedLibrary(new String[] {"a.dex", "b.dex"});
         String[] contexts = DexoptUtils.getClassLoaderContexts(
                 data.info, sharedLibrary, data.pathsWithCode);
 
         assertEquals(1, contexts.length);
-        assertEquals("PCL[a.dex:b.dex]", contexts[0]);
+        assertEquals("PCL[]{PCL[a.dex:b.dex]}", contexts[0]);
     }
 
     @Test
     public void tesNoSplitDelegateLast() {
         TestData data = createMockApplicationInfo(
                 DELEGATE_LAST_CLASS_LOADER_NAME, false, false);
-        String[] sharedLibrary = new String[] {"a.dex", "b.dex"};
+        List<SharedLibraryInfo> sharedLibrary =
+                createMockSharedLibrary(new String[] {"a.dex", "b.dex"});
         String[] contexts = DexoptUtils.getClassLoaderContexts(
                 data.info, sharedLibrary, data.pathsWithCode);
 
         assertEquals(1, contexts.length);
-        assertEquals("DLC[a.dex:b.dex]", contexts[0]);
+        assertEquals("DLC[]{PCL[a.dex:b.dex]}", contexts[0]);
     }
 
     @Test
@@ -276,7 +296,8 @@
         TestData data = createMockApplicationInfo(null, true, false);
         Arrays.fill(data.pathsWithCode, false);
 
-        String[] sharedLibrary = new String[] {"a.dex", "b.dex"};
+        List<SharedLibraryInfo> sharedLibrary =
+                createMockSharedLibrary(new String[] {"a.dex", "b.dex"});
         String[] contexts = DexoptUtils.getClassLoaderContexts(
                 data.info, sharedLibrary, data.pathsWithCode);
 
@@ -295,18 +316,21 @@
     public void testContextBaseNoCode() {
         TestData data = createMockApplicationInfo(null, true, true);
         data.pathsWithCode[0] = false;
-        String[] sharedLibrary = new String[] {"a.dex", "b.dex"};
+        List<SharedLibraryInfo> sharedLibrary =
+                createMockSharedLibrary(new String[] {"a.dex", "b.dex"});
         String[] contexts = DexoptUtils.getClassLoaderContexts(
                 data.info, sharedLibrary, data.pathsWithCode);
 
         assertEquals(9, contexts.length);
         assertEquals(null, contexts[0]);
-        assertEquals("DLC[];DLC[base-2.dex];PCL[base-4.dex];PCL[a.dex:b.dex:base.dex]", contexts[1]);
-        assertEquals("DLC[];PCL[base-4.dex];PCL[a.dex:b.dex:base.dex]", contexts[2]);
-        assertEquals("PCL[];PCL[base-4.dex];PCL[a.dex:b.dex:base.dex]", contexts[3]);
-        assertEquals("PCL[];PCL[a.dex:b.dex:base.dex]", contexts[4]);
-        assertEquals("PCL[];PCL[a.dex:b.dex:base.dex]", contexts[5]);
-        assertEquals("PCL[];PCL[base-5.dex];PCL[a.dex:b.dex:base.dex]", contexts[6]);
+        assertEquals(
+                "DLC[];DLC[base-2.dex];PCL[base-4.dex];PCL[base.dex]{PCL[a.dex:b.dex]}",
+                contexts[1]);
+        assertEquals("DLC[];PCL[base-4.dex];PCL[base.dex]{PCL[a.dex:b.dex]}", contexts[2]);
+        assertEquals("PCL[];PCL[base-4.dex];PCL[base.dex]{PCL[a.dex:b.dex]}", contexts[3]);
+        assertEquals("PCL[];PCL[base.dex]{PCL[a.dex:b.dex]}", contexts[4]);
+        assertEquals("PCL[];PCL[base.dex]{PCL[a.dex:b.dex]}", contexts[5]);
+        assertEquals("PCL[];PCL[base-5.dex];PCL[base.dex]{PCL[a.dex:b.dex]}", contexts[6]);
         assertEquals(null, contexts[7]);
     }