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

Commit 566b1c80 authored by Treehugger Robot's avatar Treehugger Robot Committed by Gerrit Code Review
Browse files

Merge "Precreate the classloader for the WebView."

parents c6c005ef 3b6ca99b
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;
        }
    }