Merge "Revert "Fix shared libraries not being reported via Reporter"" am: 23dde6accb am: 420ff1b50b

Change-Id: Ib6f7bbefed0ff9897d80479308c3724954d42e26
diff --git a/dalvik/src/main/java/dalvik/system/BaseDexClassLoader.java b/dalvik/src/main/java/dalvik/system/BaseDexClassLoader.java
index 4a9e8631..d0a449b 100644
--- a/dalvik/src/main/java/dalvik/system/BaseDexClassLoader.java
+++ b/dalvik/src/main/java/dalvik/system/BaseDexClassLoader.java
@@ -24,11 +24,8 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
-import java.util.Collections;
 import java.util.Enumeration;
-import java.util.HashMap;
 import java.util.List;
-import java.util.Map;
 import sun.misc.CompoundEnumeration;
 
 /**
@@ -137,17 +134,28 @@
      * Reports the current class loader chain to the registered {@code reporter}.
      */
     private void reportClassLoaderChain() {
-        String[] classPathAndClassLoaderContexts = computeClassLoaderContextsNative();
-        if (classPathAndClassLoaderContexts.length == 0) {
-            return;
+        ArrayList<ClassLoader> classLoadersChain = new ArrayList<>();
+        ArrayList<String> classPaths = new ArrayList<>();
+
+        classLoadersChain.add(this);
+        classPaths.add(String.join(File.pathSeparator, pathList.getDexPaths()));
+
+        ClassLoader bootClassLoader = ClassLoader.getSystemClassLoader().getParent();
+        ClassLoader current = getParent();
+
+        while (current != null && current != bootClassLoader) {
+            classLoadersChain.add(current);
+            if (current instanceof BaseDexClassLoader) {
+                BaseDexClassLoader bdcCurrent = (BaseDexClassLoader) current;
+                classPaths.add(String.join(File.pathSeparator, bdcCurrent.pathList.getDexPaths()));
+            } else {
+                // We can't determine the classpath for arbitrary class loaders.
+                classPaths.add(null);
+            }
+            current = current.getParent();
         }
-        Map<String, String> dexFileMapping =
-                new HashMap<>(classPathAndClassLoaderContexts.length / 2);
-        for (int i = 0; i < classPathAndClassLoaderContexts.length; i += 2) {
-            dexFileMapping.put(classPathAndClassLoaderContexts[i],
-                    classPathAndClassLoaderContexts[i + 1]);
-        }
-        reporter.report(Collections.unmodifiableMap(dexFileMapping));
+
+        reporter.report(classLoadersChain, classPaths);
     }
 
     /**
@@ -365,16 +373,19 @@
     @libcore.api.CorePlatformApi
     public interface Reporter {
         /**
-         * Reports the construction of a BaseDexClassLoader and provides opaque information about
-         * the class loader chain. For example, if the childmost ClassLoader in the chain:
-         * {@quote BaseDexClassLoader { foo.dex } -> BaseDexClassLoader { base.apk } 
-         *    -> BootClassLoader } was just initialized then the load of {@code "foo.dex"} would be
-         * reported with a classLoaderContext of {@code "PCL[];PCL[base.apk]"}.
+         * Reports the construction of a BaseDexClassLoader and provides information about the
+         * class loader chain.
          *
-         * @param contextsMap A map from dex file paths to the class loader context used to load
-         *     each dex file.
+         * @param classLoadersChain the chain of class loaders used during the construction of the
+         *     class loader. The first element is the BaseDexClassLoader being constructed,
+         *     the second element is its parent, and so on.
+         * @param classPaths the class paths of the class loaders present in
+         *     {@param classLoadersChain}. The first element corresponds to the first class
+         *     loader and so on. A classpath is represented as a list of dex files separated by
+         *     {@code File.pathSeparator}. If the class loader is not a BaseDexClassLoader the
+         *     classpath will be null.
          */
         @libcore.api.CorePlatformApi
-        void report(Map<String, String> contextsMap);
+        void report(List<ClassLoader> classLoadersChain, List<String> classPaths);
     }
 }
diff --git a/luni/src/test/java/libcore/dalvik/system/BaseDexClassLoaderTest.java b/luni/src/test/java/libcore/dalvik/system/BaseDexClassLoaderTest.java
index ba7c232..1642a11 100644
--- a/luni/src/test/java/libcore/dalvik/system/BaseDexClassLoaderTest.java
+++ b/luni/src/test/java/libcore/dalvik/system/BaseDexClassLoaderTest.java
@@ -33,9 +33,7 @@
 import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.Collections;
 import java.util.Enumeration;
-import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
@@ -50,15 +48,18 @@
 @RunWith(JUnit4.class)
 public final class BaseDexClassLoaderTest {
     private static class Reporter implements BaseDexClassLoader.Reporter {
-        public final Map<String, String> loadedDexMapping = new HashMap<String, String>();
+        public final List<ClassLoader> classLoaders = new ArrayList<>();
+        public final List<String> loadedDexPaths = new ArrayList<>();
 
         @Override
-        public void report(Map<String, String> contextMap) {
-            loadedDexMapping.putAll(contextMap);
+        public void report(List<ClassLoader> loaders, List<String> dexPaths) {
+            classLoaders.addAll(loaders);
+            loadedDexPaths.addAll(dexPaths);
         }
 
         void reset() {
-            loadedDexMapping.clear();
+            classLoaders.clear();
+            loadedDexPaths.clear();
         }
     }
 
@@ -121,9 +122,17 @@
         BaseDexClassLoader cl1 = new PathClassLoader(jar.getPath(),
             ClassLoader.getSystemClassLoader());
 
-        // Verify the reported data. The only class loader context should be two empty PCLs
-        // (the system class loader is a PCL)
-        assertEquals(Map.of(jar.getPath(), "PCL[];PCL[]"), reporter.loadedDexMapping);
+        // Verify the reported data.
+        assertEquals(2, reporter.loadedDexPaths.size());
+        assertEquals(2, reporter.classLoaders.size());
+
+        // First class loader should be the one loading the files
+        assertEquals(jar.getPath(), reporter.loadedDexPaths.get(0));
+        assertEquals(cl1, reporter.classLoaders.get(0));
+
+        // Second class loader should be the system class loader.
+        // Don't check the actual classpath as that might vary based on system properties.
+        assertEquals(ClassLoader.getSystemClassLoader(), reporter.classLoaders.get(1));
     }
 
     @Test
@@ -132,10 +141,16 @@
         ClassLoader unknownLoader = new ClassLoader(ClassLoader.getSystemClassLoader()) {};
         BaseDexClassLoader cl1 = new PathClassLoader(jar.getPath(), unknownLoader);
 
-        // Verify the dex path gets reported, but with no class loader context due to the foreign
-        // class loader.
-        assertEquals(Map.of(jar.getPath(), "=UnsupportedClassLoaderContext="),
-                reporter.loadedDexMapping);
+        assertEquals(3, reporter.loadedDexPaths.size());
+        assertEquals(3, reporter.classLoaders.size());
+
+        assertEquals(jar.getPath(), reporter.loadedDexPaths.get(0));
+        assertEquals(cl1, reporter.classLoaders.get(0));
+
+        assertNull(reporter.loadedDexPaths.get(1));
+        assertEquals(unknownLoader, reporter.classLoaders.get(1));
+
+        assertEquals(ClassLoader.getSystemClassLoader(), reporter.classLoaders.get(2));
     }
 
     @Test
@@ -143,7 +158,8 @@
         BaseDexClassLoader cl1 = new PathClassLoader(jar.getPath(),
             ClassLoader.getSystemClassLoader());
 
-        assertEquals(Map.of(jar.getPath(), "PCL[];PCL[]"), reporter.loadedDexMapping);
+        assertEquals(2, reporter.loadedDexPaths.size());
+        assertEquals(2, reporter.classLoaders.size());
 
         // Check we don't report after the reporter is unregistered.
         unregisterReporter();
@@ -153,67 +169,8 @@
         BaseDexClassLoader cl2 = new PathClassLoader(jar.getPath(), pcl);
 
         // Verify nothing reported
-        assertEquals(Map.<String, String>of(), reporter.loadedDexMapping);
-    }
-
-    @Test
-    public void testReporting_multipleJars() throws Exception {
-        // Load the jar file using a PathClassLoader.
-        BaseDexClassLoader cl1 = new PathClassLoader(
-            String.join(File.pathSeparator, jar.getPath(), jar2.getPath()),
-            ClassLoader.getSystemClassLoader());
-
-        // The first class loader context should be two empty PCLs (the system class loader is a
-        // PCL) and the second should be the same, but the bottom classloader contains the first
-        // jar.
-        assertEquals(Map.of(jar.getPath(), "PCL[];PCL[]",
-                            jar2.getPath(), "PCL[" + jar.getPath() + "];PCL[]"),
-                reporter.loadedDexMapping);
-    }
-
-    @Test
-    public void testReporting_withSharedLibraries() throws Exception {
-        final ClassLoader parent = ClassLoader.getSystemClassLoader();
-        final ClassLoader sharedLoaders[] = new ClassLoader[] {
-            new PathClassLoader(jar2.getPath(), /* librarySearchPath */ null, parent),
-        };
-        // Reset so we don't get load reports from creating the shared library CL
-        reporter.reset();
-
-        BaseDexClassLoader bdcl = new PathClassLoader(jar.getPath(), null, parent, sharedLoaders);
-
-        // Verify the loaded dex file contains jar2 encoded as a shared library in its encoded class
-        // loader context.
-        assertEquals(
-                Map.of(jar.getPath(), "PCL[]{PCL[" + jar2.getPath() + "];PCL[]};PCL[]"),
-                reporter.loadedDexMapping);
-    }
-
-    @Test
-    public void testReporting_multipleJars_withSharedLibraries() throws Exception {
-        final ClassLoader parent = ClassLoader.getSystemClassLoader();
-        final String sharedJarPath = resourcesMap.get("parent.jar").getAbsolutePath();
-        final ClassLoader sharedLoaders[] = new ClassLoader[] {
-            new PathClassLoader(sharedJarPath, /* librarySearchPath */ null, parent),
-        };
-        // Reset so we don't get load reports from creating the shared library CL
-        reporter.reset();
-
-        BaseDexClassLoader bdcl = new PathClassLoader(
-                String.join(File.pathSeparator, jar.getPath(), jar2.getPath()),
-                null, parent, sharedLoaders);
-
-        final String contextSuffix = "{PCL[" + sharedJarPath + "];PCL[]};PCL[]";
-
-        assertEquals(Map.of(jar.getPath(), "PCL[]" + contextSuffix,
-                            jar2.getPath(), "PCL[" + jar.getPath() + "]" + contextSuffix),
-                reporter.loadedDexMapping);
-    }
-
-    @Test
-    public void testReporting_emptyPath() throws Exception {
-        BaseDexClassLoader cl1 = new PathClassLoader("", ClassLoader.getSystemClassLoader());
-        assertEquals(Map.<String, String>of(), reporter.loadedDexMapping);
+        assertEquals(0, reporter.loadedDexPaths.size());
+        assertEquals(0, reporter.classLoaders.size());
     }
 
     /* package */ static List<String> readResources(ClassLoader cl, String resourceName)
diff --git a/mmodules/core_platform_api/api/platform/current-api.txt b/mmodules/core_platform_api/api/platform/current-api.txt
index 1ca16bc..707e3a3 100644
--- a/mmodules/core_platform_api/api/platform/current-api.txt
+++ b/mmodules/core_platform_api/api/platform/current-api.txt
@@ -535,7 +535,7 @@
   }
 
   public static interface BaseDexClassLoader.Reporter {
-    method public void report(java.util.Map<java.lang.String,java.lang.String>);
+    method public void report(java.util.List<java.lang.ClassLoader>, java.util.List<java.lang.String>);
   }
 
   public final class BlockGuard {