Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4b5ca28d authored by Steven Moreland's avatar Steven Moreland Committed by Gerrit Code Review
Browse files

Merge "Revert "Revert "Preload non-bootclasspath Java lib ClassLoaders."""

parents 9c706654 bdc2702c
Loading
Loading
Loading
Loading
+150 −1
Original line number Diff line number Diff line
@@ -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;
@@ -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,
@@ -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;
            }

@@ -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
@@ -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;
}
+1 −1
Original line number Diff line number Diff line
@@ -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);
+31 −0
Original line number Diff line number Diff line
@@ -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;
@@ -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
@@ -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.
     *