Merge "Precreate the classloader for the WebView."
am: 566b1c80e4
Change-Id: Ic79079748dae515cb8d89ef99148755ac65f1d47
This commit is contained in:
committed by
android-build-merger
commit
1feb782f01
@ -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);
|
||||
|
||||
/**
|
||||
|
@ -339,39 +339,43 @@ public final class LoadedApk {
|
||||
* concatenation of both apps' shared library lists.
|
||||
*/
|
||||
|
||||
String instrumentationPackageName = activityThread.mInstrumentationPackageName;
|
||||
String instrumentationAppDir = activityThread.mInstrumentationAppDir;
|
||||
String[] instrumentationSplitAppDirs = activityThread.mInstrumentationSplitAppDirs;
|
||||
String instrumentationLibDir = activityThread.mInstrumentationLibDir;
|
||||
|
||||
String instrumentedAppDir = activityThread.mInstrumentedAppDir;
|
||||
String[] instrumentedSplitAppDirs = activityThread.mInstrumentedSplitAppDirs;
|
||||
String instrumentedLibDir = activityThread.mInstrumentedLibDir;
|
||||
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;
|
||||
String instrumentationLibDir = activityThread.mInstrumentationLibDir;
|
||||
|
||||
if (appDir.equals(instrumentationAppDir)
|
||||
|| appDir.equals(instrumentedAppDir)) {
|
||||
outZipPaths.clear();
|
||||
outZipPaths.add(instrumentationAppDir);
|
||||
if (instrumentationSplitAppDirs != null) {
|
||||
Collections.addAll(outZipPaths, instrumentationSplitAppDirs);
|
||||
}
|
||||
if (!instrumentationAppDir.equals(instrumentedAppDir)) {
|
||||
outZipPaths.add(instrumentedAppDir);
|
||||
if (instrumentedSplitAppDirs != null) {
|
||||
Collections.addAll(outZipPaths, instrumentedSplitAppDirs);
|
||||
String instrumentedAppDir = activityThread.mInstrumentedAppDir;
|
||||
String[] instrumentedSplitAppDirs = activityThread.mInstrumentedSplitAppDirs;
|
||||
String instrumentedLibDir = activityThread.mInstrumentedLibDir;
|
||||
|
||||
if (appDir.equals(instrumentationAppDir)
|
||||
|| appDir.equals(instrumentedAppDir)) {
|
||||
outZipPaths.clear();
|
||||
outZipPaths.add(instrumentationAppDir);
|
||||
if (instrumentationSplitAppDirs != null) {
|
||||
Collections.addAll(outZipPaths, instrumentationSplitAppDirs);
|
||||
}
|
||||
}
|
||||
|
||||
if (outLibPaths != null) {
|
||||
outLibPaths.add(instrumentationLibDir);
|
||||
if (!instrumentationLibDir.equals(instrumentedLibDir)) {
|
||||
outLibPaths.add(instrumentedLibDir);
|
||||
if (!instrumentationAppDir.equals(instrumentedAppDir)) {
|
||||
outZipPaths.add(instrumentedAppDir);
|
||||
if (instrumentedSplitAppDirs != null) {
|
||||
Collections.addAll(outZipPaths, instrumentedSplitAppDirs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!instrumentedAppDir.equals(instrumentationAppDir)) {
|
||||
instrumentationLibs = getLibrariesFor(instrumentationPackageName);
|
||||
if (outLibPaths != null) {
|
||||
outLibPaths.add(instrumentationLibDir);
|
||||
if (!instrumentationLibDir.equals(instrumentedLibDir)) {
|
||||
outLibPaths.add(instrumentedLibDir);
|
||||
}
|
||||
}
|
||||
|
||||
if (!instrumentedAppDir.equals(instrumentationAppDir)) {
|
||||
instrumentationLibs = getLibrariesFor(instrumentationPackageName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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 =
|
||||
|
@ -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;
|
||||
// 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 " + packagePath + " " + libsPath);
|
||||
sZygote.preloadPackageForAbi(packagePath, libsPath, Build.SUPPORTED_ABIS[0]);
|
||||
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;
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user