Loading core/java/android/app/ApplicationLoaders.java +150 −1 Original line number Diff line number Diff line Loading @@ -17,20 +17,27 @@ package android.app; import android.annotation.UnsupportedAppUsage; import android.content.pm.SharedLibraryInfo; import android.os.Build; import android.os.GraphicsEnvironment; import android.os.Trace; import android.util.ArrayMap; import android.util.Log; import com.android.internal.os.ClassLoaderFactory; import dalvik.system.PathClassLoader; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; /** @hide */ public class ApplicationLoaders { private static final String TAG = "ApplicationLoaders"; @UnsupportedAppUsage public static ApplicationLoaders getDefault() { return gApplicationLoaders; Loading @@ -54,6 +61,26 @@ public class ApplicationLoaders { libraryPermittedPath, parent, zip, classLoaderName, sharedLibraries); } /** * Gets a class loader for a shared library. Additional dependent shared libraries are allowed * to be specified (sharedLibraries). * * Additionally, as an optimization, this will return a pre-created ClassLoader if one has * been cached by createAndCacheNonBootclasspathSystemClassLoaders. */ ClassLoader getSharedLibraryClassLoaderWithSharedLibraries(String zip, int targetSdkVersion, boolean isBundled, String librarySearchPath, String libraryPermittedPath, ClassLoader parent, String classLoaderName, List<ClassLoader> sharedLibraries) { ClassLoader loader = getCachedNonBootclasspathSystemLib(zip, parent, classLoaderName, sharedLibraries); if (loader != null) { return loader; } return getClassLoaderWithSharedLibraries(zip, targetSdkVersion, isBundled, librarySearchPath, libraryPermittedPath, parent, classLoaderName, sharedLibraries); } private ClassLoader getClassLoader(String zip, int targetSdkVersion, boolean isBundled, String librarySearchPath, String libraryPermittedPath, ClassLoader parent, String cacheKey, Loading Loading @@ -95,7 +122,9 @@ public class ApplicationLoaders { classloader, librarySearchPath, libraryPermittedPath); Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); if (cacheKey != null) { mLoaders.put(cacheKey, classloader); } return classloader; } Loading @@ -107,6 +136,112 @@ public class ApplicationLoaders { } } /** * Caches system library class loaders which are not on the bootclasspath but are still used * by many system apps. * * All libraries in the closure of libraries to be loaded must be in libs. A library can * only depend on libraries that come before it in the list. */ public void createAndCacheNonBootclasspathSystemClassLoaders(SharedLibraryInfo[] libs) { if (mSystemLibsCacheMap != null) { Log.wtf(TAG, "Already cached."); return; } mSystemLibsCacheMap = new HashMap<String, CachedClassLoader>(); for (SharedLibraryInfo lib : libs) { createAndCacheNonBootclasspathSystemClassLoader(lib); } } /** * Caches a single non-bootclasspath class loader. * * All of this library's dependencies must have previously been cached. */ private void createAndCacheNonBootclasspathSystemClassLoader(SharedLibraryInfo lib) { String path = lib.getPath(); List<SharedLibraryInfo> dependencies = lib.getDependencies(); // get cached classloaders for dependencies ArrayList<ClassLoader> sharedLibraries = null; if (dependencies != null) { sharedLibraries = new ArrayList<ClassLoader>(dependencies.size()); for (SharedLibraryInfo dependency : dependencies) { String dependencyPath = dependency.getPath(); CachedClassLoader cached = mSystemLibsCacheMap.get(dependencyPath); if (cached == null) { Log.e(TAG, "Failed to find dependency " + dependencyPath + " of cached library " + path); return; } sharedLibraries.add(cached.loader); } } // assume cached libraries work with current sdk since they are built-in ClassLoader classLoader = getClassLoader(path, Build.VERSION.SDK_INT, true /*isBundled*/, null /*librarySearchPath*/, null /*libraryPermittedPath*/, null /*parent*/, null /*cacheKey*/, null /*classLoaderName*/, sharedLibraries /*sharedLibraries*/); if (classLoader == null) { Log.e(TAG, "Failed to cache " + path); return; } CachedClassLoader cached = new CachedClassLoader(); cached.loader = classLoader; cached.sharedLibraries = sharedLibraries; Log.d(TAG, "Created zygote-cached class loader: " + path); mSystemLibsCacheMap.put(path, cached); } private static boolean sharedLibrariesEquals(List<ClassLoader> lhs, List<ClassLoader> rhs) { if (lhs == null) { return rhs == null; } return lhs.equals(rhs); } /** * Returns lib cached with createAndCacheNonBootclasspathSystemClassLoader. This is called by * the zygote during caching. * * If there is an error or the cache is not available, this returns null. */ private ClassLoader getCachedNonBootclasspathSystemLib(String zip, ClassLoader parent, String classLoaderName, List<ClassLoader> sharedLibraries) { if (mSystemLibsCacheMap == null) { return null; } // we only cache top-level libs with the default class loader if (parent != null || classLoaderName != null) { return null; } CachedClassLoader cached = mSystemLibsCacheMap.get(zip); if (cached == null) { return null; } // cached must be built and loaded in the same environment if (!sharedLibrariesEquals(sharedLibraries, cached.sharedLibraries)) { Log.w(TAG, "Unexpected environment for cached library: (" + sharedLibraries + "|" + cached.sharedLibraries + ")"); return null; } Log.d(TAG, "Returning zygote-cached class loader: " + zip); return cached.loader; } /** * Creates a classloader for the WebView APK and places it in the cache of loaders maintained * by this class. This is used in the WebView zygote, where its presence in the cache speeds up Loading Loading @@ -151,4 +286,18 @@ public class ApplicationLoaders { private final ArrayMap<String, ClassLoader> mLoaders = new ArrayMap<>(); private static final ApplicationLoaders gApplicationLoaders = new ApplicationLoaders(); private static class CachedClassLoader { ClassLoader loader; /** * The shared libraries used when constructing loader for verification. */ List<ClassLoader> sharedLibraries; } /** * This is a map of zip to associated class loader. */ private Map<String, CachedClassLoader> mSystemLibsCacheMap = null; } core/java/android/app/LoadedApk.java +1 −1 Original line number Diff line number Diff line Loading @@ -675,7 +675,7 @@ public final class LoadedApk { // 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, return ApplicationLoaders.getDefault().getSharedLibraryClassLoaderWithSharedLibraries(jars, mApplicationInfo.targetSdkVersion, isBundledApp, librarySearchPath, libraryPermittedPath, /* parent */ null, /* classLoaderName */ null, sharedLibraries); Loading core/java/com/android/internal/os/ZygoteInit.java +31 −0 Original line number Diff line number Diff line Loading @@ -22,6 +22,8 @@ import static android.system.OsConstants.S_IRWXO; import android.annotation.UnsupportedAppUsage; import android.content.res.Resources; import android.content.res.TypedArray; import android.app.ApplicationLoaders; import android.content.pm.SharedLibraryInfo; import android.os.Build; import android.os.Environment; import android.os.IInstalld; Loading Loading @@ -141,6 +143,9 @@ public class ZygoteInit { bootTimingsTraceLog.traceBegin("PreloadClasses"); preloadClasses(); bootTimingsTraceLog.traceEnd(); // PreloadClasses bootTimingsTraceLog.traceBegin("CacheNonBootClasspathClassLoaders"); cacheNonBootClasspathClassLoaders(); bootTimingsTraceLog.traceEnd(); // CacheNonBootClasspathClassLoaders bootTimingsTraceLog.traceBegin("PreloadResources"); preloadResources(); bootTimingsTraceLog.traceEnd(); // PreloadResources Loading Loading @@ -346,6 +351,32 @@ public class ZygoteInit { } } /** * Load in things which are used by many apps but which cannot be put in the boot * classpath. */ private static void cacheNonBootClasspathClassLoaders() { // These libraries used to be part of the bootclasspath, but had to be removed. // Old system applications still get them for backwards compatibility reasons, // so they are cached here in order to preserve performance characteristics. SharedLibraryInfo hidlBase = new SharedLibraryInfo( "/system/framework/android.hidl.base-V1.0-java.jar", null /*packageName*/, null /*codePaths*/, null /*name*/, 0 /*version*/, SharedLibraryInfo.TYPE_BUILTIN, null /*declaringPackage*/, null /*dependentPackages*/, null /*dependencies*/); SharedLibraryInfo hidlManager = new SharedLibraryInfo( "/system/framework/android.hidl.manager-V1.0-java.jar", null /*packageName*/, null /*codePaths*/, null /*name*/, 0 /*version*/, SharedLibraryInfo.TYPE_BUILTIN, null /*declaringPackage*/, null /*dependentPackages*/, null /*dependencies*/); hidlManager.addDependency(hidlBase); ApplicationLoaders.getDefault().createAndCacheNonBootclasspathSystemClassLoaders( new SharedLibraryInfo[]{ // ordered dependencies first hidlBase, hidlManager, }); } /** * Load in commonly used resources, so they can be shared across processes. * Loading Loading
core/java/android/app/ApplicationLoaders.java +150 −1 Original line number Diff line number Diff line Loading @@ -17,20 +17,27 @@ package android.app; import android.annotation.UnsupportedAppUsage; import android.content.pm.SharedLibraryInfo; import android.os.Build; import android.os.GraphicsEnvironment; import android.os.Trace; import android.util.ArrayMap; import android.util.Log; import com.android.internal.os.ClassLoaderFactory; import dalvik.system.PathClassLoader; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; /** @hide */ public class ApplicationLoaders { private static final String TAG = "ApplicationLoaders"; @UnsupportedAppUsage public static ApplicationLoaders getDefault() { return gApplicationLoaders; Loading @@ -54,6 +61,26 @@ public class ApplicationLoaders { libraryPermittedPath, parent, zip, classLoaderName, sharedLibraries); } /** * Gets a class loader for a shared library. Additional dependent shared libraries are allowed * to be specified (sharedLibraries). * * Additionally, as an optimization, this will return a pre-created ClassLoader if one has * been cached by createAndCacheNonBootclasspathSystemClassLoaders. */ ClassLoader getSharedLibraryClassLoaderWithSharedLibraries(String zip, int targetSdkVersion, boolean isBundled, String librarySearchPath, String libraryPermittedPath, ClassLoader parent, String classLoaderName, List<ClassLoader> sharedLibraries) { ClassLoader loader = getCachedNonBootclasspathSystemLib(zip, parent, classLoaderName, sharedLibraries); if (loader != null) { return loader; } return getClassLoaderWithSharedLibraries(zip, targetSdkVersion, isBundled, librarySearchPath, libraryPermittedPath, parent, classLoaderName, sharedLibraries); } private ClassLoader getClassLoader(String zip, int targetSdkVersion, boolean isBundled, String librarySearchPath, String libraryPermittedPath, ClassLoader parent, String cacheKey, Loading Loading @@ -95,7 +122,9 @@ public class ApplicationLoaders { classloader, librarySearchPath, libraryPermittedPath); Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); if (cacheKey != null) { mLoaders.put(cacheKey, classloader); } return classloader; } Loading @@ -107,6 +136,112 @@ public class ApplicationLoaders { } } /** * Caches system library class loaders which are not on the bootclasspath but are still used * by many system apps. * * All libraries in the closure of libraries to be loaded must be in libs. A library can * only depend on libraries that come before it in the list. */ public void createAndCacheNonBootclasspathSystemClassLoaders(SharedLibraryInfo[] libs) { if (mSystemLibsCacheMap != null) { Log.wtf(TAG, "Already cached."); return; } mSystemLibsCacheMap = new HashMap<String, CachedClassLoader>(); for (SharedLibraryInfo lib : libs) { createAndCacheNonBootclasspathSystemClassLoader(lib); } } /** * Caches a single non-bootclasspath class loader. * * All of this library's dependencies must have previously been cached. */ private void createAndCacheNonBootclasspathSystemClassLoader(SharedLibraryInfo lib) { String path = lib.getPath(); List<SharedLibraryInfo> dependencies = lib.getDependencies(); // get cached classloaders for dependencies ArrayList<ClassLoader> sharedLibraries = null; if (dependencies != null) { sharedLibraries = new ArrayList<ClassLoader>(dependencies.size()); for (SharedLibraryInfo dependency : dependencies) { String dependencyPath = dependency.getPath(); CachedClassLoader cached = mSystemLibsCacheMap.get(dependencyPath); if (cached == null) { Log.e(TAG, "Failed to find dependency " + dependencyPath + " of cached library " + path); return; } sharedLibraries.add(cached.loader); } } // assume cached libraries work with current sdk since they are built-in ClassLoader classLoader = getClassLoader(path, Build.VERSION.SDK_INT, true /*isBundled*/, null /*librarySearchPath*/, null /*libraryPermittedPath*/, null /*parent*/, null /*cacheKey*/, null /*classLoaderName*/, sharedLibraries /*sharedLibraries*/); if (classLoader == null) { Log.e(TAG, "Failed to cache " + path); return; } CachedClassLoader cached = new CachedClassLoader(); cached.loader = classLoader; cached.sharedLibraries = sharedLibraries; Log.d(TAG, "Created zygote-cached class loader: " + path); mSystemLibsCacheMap.put(path, cached); } private static boolean sharedLibrariesEquals(List<ClassLoader> lhs, List<ClassLoader> rhs) { if (lhs == null) { return rhs == null; } return lhs.equals(rhs); } /** * Returns lib cached with createAndCacheNonBootclasspathSystemClassLoader. This is called by * the zygote during caching. * * If there is an error or the cache is not available, this returns null. */ private ClassLoader getCachedNonBootclasspathSystemLib(String zip, ClassLoader parent, String classLoaderName, List<ClassLoader> sharedLibraries) { if (mSystemLibsCacheMap == null) { return null; } // we only cache top-level libs with the default class loader if (parent != null || classLoaderName != null) { return null; } CachedClassLoader cached = mSystemLibsCacheMap.get(zip); if (cached == null) { return null; } // cached must be built and loaded in the same environment if (!sharedLibrariesEquals(sharedLibraries, cached.sharedLibraries)) { Log.w(TAG, "Unexpected environment for cached library: (" + sharedLibraries + "|" + cached.sharedLibraries + ")"); return null; } Log.d(TAG, "Returning zygote-cached class loader: " + zip); return cached.loader; } /** * Creates a classloader for the WebView APK and places it in the cache of loaders maintained * by this class. This is used in the WebView zygote, where its presence in the cache speeds up Loading Loading @@ -151,4 +286,18 @@ public class ApplicationLoaders { private final ArrayMap<String, ClassLoader> mLoaders = new ArrayMap<>(); private static final ApplicationLoaders gApplicationLoaders = new ApplicationLoaders(); private static class CachedClassLoader { ClassLoader loader; /** * The shared libraries used when constructing loader for verification. */ List<ClassLoader> sharedLibraries; } /** * This is a map of zip to associated class loader. */ private Map<String, CachedClassLoader> mSystemLibsCacheMap = null; }
core/java/android/app/LoadedApk.java +1 −1 Original line number Diff line number Diff line Loading @@ -675,7 +675,7 @@ public final class LoadedApk { // 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, return ApplicationLoaders.getDefault().getSharedLibraryClassLoaderWithSharedLibraries(jars, mApplicationInfo.targetSdkVersion, isBundledApp, librarySearchPath, libraryPermittedPath, /* parent */ null, /* classLoaderName */ null, sharedLibraries); Loading
core/java/com/android/internal/os/ZygoteInit.java +31 −0 Original line number Diff line number Diff line Loading @@ -22,6 +22,8 @@ import static android.system.OsConstants.S_IRWXO; import android.annotation.UnsupportedAppUsage; import android.content.res.Resources; import android.content.res.TypedArray; import android.app.ApplicationLoaders; import android.content.pm.SharedLibraryInfo; import android.os.Build; import android.os.Environment; import android.os.IInstalld; Loading Loading @@ -141,6 +143,9 @@ public class ZygoteInit { bootTimingsTraceLog.traceBegin("PreloadClasses"); preloadClasses(); bootTimingsTraceLog.traceEnd(); // PreloadClasses bootTimingsTraceLog.traceBegin("CacheNonBootClasspathClassLoaders"); cacheNonBootClasspathClassLoaders(); bootTimingsTraceLog.traceEnd(); // CacheNonBootClasspathClassLoaders bootTimingsTraceLog.traceBegin("PreloadResources"); preloadResources(); bootTimingsTraceLog.traceEnd(); // PreloadResources Loading Loading @@ -346,6 +351,32 @@ public class ZygoteInit { } } /** * Load in things which are used by many apps but which cannot be put in the boot * classpath. */ private static void cacheNonBootClasspathClassLoaders() { // These libraries used to be part of the bootclasspath, but had to be removed. // Old system applications still get them for backwards compatibility reasons, // so they are cached here in order to preserve performance characteristics. SharedLibraryInfo hidlBase = new SharedLibraryInfo( "/system/framework/android.hidl.base-V1.0-java.jar", null /*packageName*/, null /*codePaths*/, null /*name*/, 0 /*version*/, SharedLibraryInfo.TYPE_BUILTIN, null /*declaringPackage*/, null /*dependentPackages*/, null /*dependencies*/); SharedLibraryInfo hidlManager = new SharedLibraryInfo( "/system/framework/android.hidl.manager-V1.0-java.jar", null /*packageName*/, null /*codePaths*/, null /*name*/, 0 /*version*/, SharedLibraryInfo.TYPE_BUILTIN, null /*declaringPackage*/, null /*dependentPackages*/, null /*dependencies*/); hidlManager.addDependency(hidlBase); ApplicationLoaders.getDefault().createAndCacheNonBootclasspathSystemClassLoaders( new SharedLibraryInfo[]{ // ordered dependencies first hidlBase, hidlManager, }); } /** * Load in commonly used resources, so they can be shared across processes. * Loading