Loading core/java/android/app/ApplicationLoaders.java +17 −2 Original line number Diff line number Diff line Loading @@ -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) { /* Loading Loading @@ -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); /** Loading core/java/android/app/LoadedApk.java +32 −28 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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)) { Loading @@ -374,6 +377,7 @@ public final class LoadedApk { instrumentationLibs = getLibrariesFor(instrumentationPackageName); } } } if (outLibPaths != null) { if (outLibPaths.isEmpty()) { Loading core/java/android/webkit/WebViewFactory.java +3 −1 Original line number Diff line number Diff line Loading @@ -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 = Loading core/java/android/webkit/WebViewZygote.java +20 −5 Original line number Diff line number Diff line Loading @@ -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 */ Loading Loading @@ -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; Loading core/java/com/android/internal/os/WebViewZygoteInit.java +24 −1 Original line number Diff line number Diff line Loading @@ -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. Loading Loading @@ -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; } } Loading Loading
core/java/android/app/ApplicationLoaders.java +17 −2 Original line number Diff line number Diff line Loading @@ -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) { /* Loading Loading @@ -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); /** Loading
core/java/android/app/LoadedApk.java +32 −28 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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)) { Loading @@ -374,6 +377,7 @@ public final class LoadedApk { instrumentationLibs = getLibrariesFor(instrumentationPackageName); } } } if (outLibPaths != null) { if (outLibPaths.isEmpty()) { Loading
core/java/android/webkit/WebViewFactory.java +3 −1 Original line number Diff line number Diff line Loading @@ -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 = Loading
core/java/android/webkit/WebViewZygote.java +20 −5 Original line number Diff line number Diff line Loading @@ -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 */ Loading Loading @@ -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; Loading
core/java/com/android/internal/os/WebViewZygoteInit.java +24 −1 Original line number Diff line number Diff line Loading @@ -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. Loading Loading @@ -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; } } Loading