Merge "Preload non-bootclasspath Java lib ClassLoaders." am: 213812ba28
am: 625d63ed64
Change-Id: Ie3c5931c981095e574e9dcadf8ed88686749116a
This commit is contained in:
@@ -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;
|
||||||
@@ -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,
|
||||||
@@ -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);
|
||||||
|
|
||||||
mLoaders.put(cacheKey, classloader);
|
if (cacheKey != null) {
|
||||||
|
mLoaders.put(cacheKey, classloader);
|
||||||
|
}
|
||||||
return classloader;
|
return classloader;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -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
|
||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -675,7 +675,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);
|
||||||
|
|||||||
@@ -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;
|
||||||
@@ -141,6 +143,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
|
||||||
@@ -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.
|
* Load in commonly used resources, so they can be shared across processes.
|
||||||
*
|
*
|
||||||
|
|||||||
Reference in New Issue
Block a user