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

Commit 7e17c6b0 authored by Torne (Richard Coles)'s avatar Torne (Richard Coles) Committed by android-build-merger
Browse files

Merge "Precreate the classloader for the WebView." am: 566b1c80 am: 1feb782f

am: 9565860b

Change-Id: I070288a127cbaa08f05b49f66e23ea0ec298040b
parents 059022bc 9565860b
Loading
Loading
Loading
Loading
+17 −2
Original line number Diff line number Diff line
@@ -16,17 +16,19 @@

package android.app;

import android.os.Build;
import android.os.Trace;
import android.util.ArrayMap;
import com.android.internal.os.PathClassLoaderFactory;
import dalvik.system.PathClassLoader;

class ApplicationLoaders {
/** @hide */
public class ApplicationLoaders {
    public static ApplicationLoaders getDefault() {
        return gApplicationLoaders;
    }

    public ClassLoader getClassLoader(String zip, int targetSdkVersion, boolean isBundled,
    ClassLoader getClassLoader(String zip, int targetSdkVersion, boolean isBundled,
                                      String librarySearchPath, String libraryPermittedPath,
                                      ClassLoader parent) {
        /*
@@ -80,6 +82,19 @@ class ApplicationLoaders {
        }
    }

    /**
     * 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
     * startup and enables memory sharing.
     */
    public ClassLoader createAndCacheWebViewClassLoader(String packagePath, String libsPath) {
      // The correct paths are calculated by WebViewZygote in the system server and passed to
      // us here. We hardcode the other parameters: WebView always targets the current SDK,
      // does not need to use non-public system libraries, and uses the base classloader as its
      // parent to permit usage of the cache.
      return getClassLoader(packagePath, Build.VERSION.SDK_INT, false, libsPath, null, null);
    }

    private static native void setupVulkanLayerPath(ClassLoader classLoader, String librarySearchPath);

    /**
+32 −28
Original line number Diff line number Diff line
@@ -339,6 +339,10 @@ public final class LoadedApk {
         * concatenation of both apps' shared library lists.
         */

        String[] instrumentationLibs = null;
        // activityThread will be null when called from the WebView zygote; just assume
        // no instrumentation applies in this case.
        if (activityThread != null) {
            String instrumentationPackageName = activityThread.mInstrumentationPackageName;
            String instrumentationAppDir = activityThread.mInstrumentationAppDir;
            String[] instrumentationSplitAppDirs = activityThread.mInstrumentationSplitAppDirs;
@@ -347,7 +351,6 @@ public final class LoadedApk {
            String instrumentedAppDir = activityThread.mInstrumentedAppDir;
            String[] instrumentedSplitAppDirs = activityThread.mInstrumentedSplitAppDirs;
            String instrumentedLibDir = activityThread.mInstrumentedLibDir;
        String[] instrumentationLibs = null;

            if (appDir.equals(instrumentationAppDir)
                    || appDir.equals(instrumentedAppDir)) {
@@ -374,6 +377,7 @@ public final class LoadedApk {
                    instrumentationLibs = getLibrariesFor(instrumentationPackageName);
                }
            }
        }

        if (outLibPaths != null) {
            if (outLibPaths.isEmpty()) {
+3 −1
Original line number Diff line number Diff line
@@ -56,7 +56,9 @@ import java.util.zip.ZipFile;
@SystemApi
public final class WebViewFactory {

    private static final String CHROMIUM_WEBVIEW_FACTORY =
    // visible for WebViewZygoteInit to look up the class by reflection and call preloadInZygote.
    /** @hide */
    public static final String CHROMIUM_WEBVIEW_FACTORY =
            "com.android.webview.chromium.WebViewChromiumFactoryProvider";

    private static final String NULL_WEBVIEW_FACTORY =
+20 −5
Original line number Diff line number Diff line
@@ -16,14 +16,19 @@

package android.webkit;

import android.app.LoadedApk;
import android.content.pm.PackageInfo;
import android.os.Build;
import android.os.SystemService;
import android.os.ZygoteProcess;
import android.text.TextUtils;
import android.util.Log;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.TimeoutException;

/** @hide */
@@ -122,11 +127,21 @@ public class WebViewZygote {
        try {
            sZygote = new ZygoteProcess("webview_zygote", null);

            String packagePath = sPackage.applicationInfo.sourceDir;
            String libsPath = sPackage.applicationInfo.nativeLibraryDir;

            Log.d(LOGTAG, "Preloading package " + packagePath + " " + libsPath);
            sZygote.preloadPackageForAbi(packagePath, libsPath, Build.SUPPORTED_ABIS[0]);
            // All the work below is usually done by LoadedApk, but the zygote can't talk to
            // PackageManager or construct a LoadedApk since it's single-threaded pre-fork, so
            // doesn't have an ActivityThread and can't use Binder.
            // Instead, figure out the paths here, in the system server where we have access to
            // the package manager. Reuse the logic from LoadedApk to determine the correct
            // paths and pass them to the zygote as strings.
            final List<String> zipPaths = new ArrayList<>(10);
            final List<String> libPaths = new ArrayList<>(10);
            LoadedApk.makePaths(null, sPackage.applicationInfo, zipPaths, libPaths);
            final String librarySearchPath = TextUtils.join(File.pathSeparator, libPaths);
            final String zip = (zipPaths.size() == 1) ? zipPaths.get(0) :
                    TextUtils.join(File.pathSeparator, zipPaths);

            Log.d(LOGTAG, "Preloading package " + zip + " " + librarySearchPath);
            sZygote.preloadPackageForAbi(zip, librarySearchPath, Build.SUPPORTED_ABIS[0]);
        } catch (Exception e) {
            Log.e(LOGTAG, "Error connecting to " + serviceName, e);
            sZygote = null;
+24 −1
Original line number Diff line number Diff line
@@ -16,14 +16,17 @@

package com.android.internal.os;

import android.app.ApplicationLoaders;
import android.net.LocalSocket;
import android.os.Build;
import android.system.ErrnoException;
import android.system.Os;
import android.text.TextUtils;
import android.util.Log;
import android.webkit.WebViewFactory;

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;

/**
 * Startup class for the WebView zygote process.
@@ -52,7 +55,27 @@ class WebViewZygoteInit {

        @Override
        protected boolean handlePreloadPackage(String packagePath, String libsPath) {
            // TODO: Use preload information to setup the ClassLoader.
            // Ask ApplicationLoaders to create and cache a classloader for the WebView APK so that
            // our children will reuse the same classloader instead of creating their own.
            // This enables us to preload Java and native code in the webview zygote process and
            // have the preloaded versions actually be used post-fork.
            ClassLoader loader = ApplicationLoaders.getDefault().createAndCacheWebViewClassLoader(
                    packagePath, libsPath);

            // Once we have the classloader, look up the WebViewFactoryProvider implementation and
            // call preloadInZygote() on it to give it the opportunity to preload the native library
            // and perform any other initialisation work that should be shared among the children.
            try {
                Class providerClass = Class.forName(WebViewFactory.CHROMIUM_WEBVIEW_FACTORY, true,
                                                    loader);
                Object result = providerClass.getMethod("preloadInZygote").invoke(null);
                if (!((Boolean)result).booleanValue()) {
                    Log.e(TAG, "preloadInZygote returned false");
                }
            } catch (ClassNotFoundException | NoSuchMethodException | SecurityException |
                     IllegalAccessException | InvocationTargetException e) {
                Log.e(TAG, "Exception while preloading package", e);
            }
            return false;
        }
    }