Merge "Revert "Fix shared libraries not being reported via Reporter"" am: 23dde6accb
Change-Id: I93292050f45e6fe8e91fba33266a7b3f8ac80970
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 {