Loading core/java/android/app/ApplicationLoaders.java +150 −1 Original line number Original line Diff line number Diff line Loading @@ -17,20 +17,27 @@ package android.app; package android.app; import android.annotation.UnsupportedAppUsage; import android.annotation.UnsupportedAppUsage; import android.content.pm.SharedLibraryInfo; import android.os.Build; import android.os.Build; import android.os.GraphicsEnvironment; import android.os.GraphicsEnvironment; import android.os.Trace; import android.os.Trace; import android.util.ArrayMap; import android.util.ArrayMap; import android.util.Log; import com.android.internal.os.ClassLoaderFactory; import com.android.internal.os.ClassLoaderFactory; import dalvik.system.PathClassLoader; import dalvik.system.PathClassLoader; import java.util.ArrayList; import java.util.Collection; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.List; import java.util.Map; /** @hide */ /** @hide */ public class ApplicationLoaders { public class ApplicationLoaders { private static final String TAG = "ApplicationLoaders"; @UnsupportedAppUsage @UnsupportedAppUsage public static ApplicationLoaders getDefault() { public static ApplicationLoaders getDefault() { return gApplicationLoaders; return gApplicationLoaders; Loading @@ -54,6 +61,26 @@ public class ApplicationLoaders { libraryPermittedPath, parent, zip, classLoaderName, sharedLibraries); 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, private ClassLoader getClassLoader(String zip, int targetSdkVersion, boolean isBundled, String librarySearchPath, String libraryPermittedPath, String librarySearchPath, String libraryPermittedPath, ClassLoader parent, String cacheKey, ClassLoader parent, String cacheKey, Loading Loading @@ -95,7 +122,9 @@ public class ApplicationLoaders { classloader, librarySearchPath, libraryPermittedPath); classloader, librarySearchPath, libraryPermittedPath); Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); if (cacheKey != null) { mLoaders.put(cacheKey, classloader); mLoaders.put(cacheKey, classloader); } return 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 * 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 * 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 final ArrayMap<String, ClassLoader> mLoaders = new ArrayMap<>(); private static final ApplicationLoaders gApplicationLoaders = new ApplicationLoaders(); 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 Original line Diff line number Diff line Loading @@ -676,7 +676,7 @@ public final class LoadedApk { // Shared libraries get a null parent: this has the side effect of having canonicalized // 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. // 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, mApplicationInfo.targetSdkVersion, isBundledApp, librarySearchPath, libraryPermittedPath, /* parent */ null, libraryPermittedPath, /* parent */ null, /* classLoaderName */ null, sharedLibraries); /* classLoaderName */ null, sharedLibraries); Loading core/java/com/android/internal/os/ZygoteInit.java +31 −0 Original line number Original line Diff line number Diff line Loading @@ -22,6 +22,8 @@ import static android.system.OsConstants.S_IRWXO; import android.annotation.UnsupportedAppUsage; import android.annotation.UnsupportedAppUsage; import android.content.res.Resources; import android.content.res.Resources; import android.content.res.TypedArray; import android.content.res.TypedArray; import android.app.ApplicationLoaders; import android.content.pm.SharedLibraryInfo; import android.os.Build; import android.os.Build; import android.os.Environment; import android.os.Environment; import android.os.IInstalld; import android.os.IInstalld; Loading Loading @@ -138,6 +140,9 @@ public class ZygoteInit { bootTimingsTraceLog.traceBegin("PreloadClasses"); bootTimingsTraceLog.traceBegin("PreloadClasses"); preloadClasses(); preloadClasses(); bootTimingsTraceLog.traceEnd(); // PreloadClasses bootTimingsTraceLog.traceEnd(); // PreloadClasses bootTimingsTraceLog.traceBegin("CacheNonBootClasspathClassLoaders"); cacheNonBootClasspathClassLoaders(); bootTimingsTraceLog.traceEnd(); // CacheNonBootClasspathClassLoaders bootTimingsTraceLog.traceBegin("PreloadResources"); bootTimingsTraceLog.traceBegin("PreloadResources"); preloadResources(); preloadResources(); bootTimingsTraceLog.traceEnd(); // PreloadResources bootTimingsTraceLog.traceEnd(); // PreloadResources Loading Loading @@ -343,6 +348,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. * 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 Original line Diff line number Diff line Loading @@ -17,20 +17,27 @@ package android.app; package android.app; import android.annotation.UnsupportedAppUsage; import android.annotation.UnsupportedAppUsage; import android.content.pm.SharedLibraryInfo; import android.os.Build; import android.os.Build; import android.os.GraphicsEnvironment; import android.os.GraphicsEnvironment; import android.os.Trace; import android.os.Trace; import android.util.ArrayMap; import android.util.ArrayMap; import android.util.Log; import com.android.internal.os.ClassLoaderFactory; import com.android.internal.os.ClassLoaderFactory; import dalvik.system.PathClassLoader; import dalvik.system.PathClassLoader; import java.util.ArrayList; import java.util.Collection; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.List; import java.util.Map; /** @hide */ /** @hide */ public class ApplicationLoaders { public class ApplicationLoaders { private static final String TAG = "ApplicationLoaders"; @UnsupportedAppUsage @UnsupportedAppUsage public static ApplicationLoaders getDefault() { public static ApplicationLoaders getDefault() { return gApplicationLoaders; return gApplicationLoaders; Loading @@ -54,6 +61,26 @@ public class ApplicationLoaders { libraryPermittedPath, parent, zip, classLoaderName, sharedLibraries); 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, private ClassLoader getClassLoader(String zip, int targetSdkVersion, boolean isBundled, String librarySearchPath, String libraryPermittedPath, String librarySearchPath, String libraryPermittedPath, ClassLoader parent, String cacheKey, ClassLoader parent, String cacheKey, Loading Loading @@ -95,7 +122,9 @@ public class ApplicationLoaders { classloader, librarySearchPath, libraryPermittedPath); classloader, librarySearchPath, libraryPermittedPath); Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); if (cacheKey != null) { mLoaders.put(cacheKey, classloader); mLoaders.put(cacheKey, classloader); } return 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 * 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 * 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 final ArrayMap<String, ClassLoader> mLoaders = new ArrayMap<>(); private static final ApplicationLoaders gApplicationLoaders = new ApplicationLoaders(); 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 Original line Diff line number Diff line Loading @@ -676,7 +676,7 @@ public final class LoadedApk { // Shared libraries get a null parent: this has the side effect of having canonicalized // 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. // 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, mApplicationInfo.targetSdkVersion, isBundledApp, librarySearchPath, libraryPermittedPath, /* parent */ null, libraryPermittedPath, /* parent */ null, /* classLoaderName */ null, sharedLibraries); /* classLoaderName */ null, sharedLibraries); Loading
core/java/com/android/internal/os/ZygoteInit.java +31 −0 Original line number Original line Diff line number Diff line Loading @@ -22,6 +22,8 @@ import static android.system.OsConstants.S_IRWXO; import android.annotation.UnsupportedAppUsage; import android.annotation.UnsupportedAppUsage; import android.content.res.Resources; import android.content.res.Resources; import android.content.res.TypedArray; import android.content.res.TypedArray; import android.app.ApplicationLoaders; import android.content.pm.SharedLibraryInfo; import android.os.Build; import android.os.Build; import android.os.Environment; import android.os.Environment; import android.os.IInstalld; import android.os.IInstalld; Loading Loading @@ -138,6 +140,9 @@ public class ZygoteInit { bootTimingsTraceLog.traceBegin("PreloadClasses"); bootTimingsTraceLog.traceBegin("PreloadClasses"); preloadClasses(); preloadClasses(); bootTimingsTraceLog.traceEnd(); // PreloadClasses bootTimingsTraceLog.traceEnd(); // PreloadClasses bootTimingsTraceLog.traceBegin("CacheNonBootClasspathClassLoaders"); cacheNonBootClasspathClassLoaders(); bootTimingsTraceLog.traceEnd(); // CacheNonBootClasspathClassLoaders bootTimingsTraceLog.traceBegin("PreloadResources"); bootTimingsTraceLog.traceBegin("PreloadResources"); preloadResources(); preloadResources(); bootTimingsTraceLog.traceEnd(); // PreloadResources bootTimingsTraceLog.traceEnd(); // PreloadResources Loading Loading @@ -343,6 +348,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. * Load in commonly used resources, so they can be shared across processes. * * Loading