Loading core/java/android/app/ApplicationLoaders.java +23 −10 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ package android.app; import android.os.Build; import android.os.Trace; import android.text.TextUtils; import android.util.ArrayMap; import com.android.internal.os.PathClassLoaderFactory; import dalvik.system.PathClassLoader; Loading @@ -31,6 +32,14 @@ public class ApplicationLoaders { ClassLoader getClassLoader(String zip, int targetSdkVersion, boolean isBundled, String librarySearchPath, String libraryPermittedPath, ClassLoader parent) { // For normal usage the cache key used is the same as the zip path. return getClassLoader(zip, targetSdkVersion, isBundled, librarySearchPath, libraryPermittedPath, parent, zip); } private ClassLoader getClassLoader(String zip, int targetSdkVersion, boolean isBundled, String librarySearchPath, String libraryPermittedPath, ClassLoader parent, String cacheKey) { /* * This is the parent we use if they pass "null" in. In theory * this should be the "system" class loader; in practice we Loading @@ -50,7 +59,7 @@ public class ApplicationLoaders { * new ClassLoader for the zip archive. */ if (parent == baseParent) { ClassLoader loader = mLoaders.get(zip); ClassLoader loader = mLoaders.get(cacheKey); if (loader != null) { return loader; } Loading @@ -71,7 +80,7 @@ public class ApplicationLoaders { setupVulkanLayerPath(pathClassloader, librarySearchPath); Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); mLoaders.put(zip, pathClassloader); mLoaders.put(cacheKey, pathClassloader); return pathClassloader; } Loading @@ -87,12 +96,16 @@ public class ApplicationLoaders { * 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) { public ClassLoader createAndCacheWebViewClassLoader(String packagePath, String libsPath, String cacheKey) { // 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); // The cache key is passed separately to enable the stub WebView to be cached under the // stub's APK path, when the actual package path is the donor APK. return getClassLoader(packagePath, Build.VERSION.SDK_INT, false, libsPath, null, null, cacheKey); } private static native void setupVulkanLayerPath(ClassLoader classLoader, String librarySearchPath); Loading core/java/android/os/ZygoteProcess.java +6 −3 Original line number Diff line number Diff line Loading @@ -487,11 +487,11 @@ public class ZygoteProcess { * Instructs the zygote to pre-load the classes and native libraries at the given paths * for the specified abi. Not all zygotes support this function. */ public void preloadPackageForAbi(String packagePath, String libsPath, String abi) throws ZygoteStartFailedEx, IOException { public void preloadPackageForAbi(String packagePath, String libsPath, String cacheKey, String abi) throws ZygoteStartFailedEx, IOException { synchronized(mLock) { ZygoteState state = openZygoteSocketIfNeeded(abi); state.writer.write("3"); state.writer.write("4"); state.writer.newLine(); state.writer.write("--preload-package"); Loading @@ -503,6 +503,9 @@ public class ZygoteProcess { state.writer.write(libsPath); state.writer.newLine(); state.writer.write(cacheKey); state.writer.newLine(); state.writer.flush(); } } Loading core/java/android/webkit/WebViewFactory.java +49 −3 Original line number Diff line number Diff line Loading @@ -280,6 +280,44 @@ public final class WebViewFactory { } } /** * If the ApplicationInfo provided is for a stub WebView, fix up the object to include the * required values from the donor package. If the ApplicationInfo is for a full WebView, * leave it alone. Throws MissingWebViewPackageException if the donor is missing. */ private static void fixupStubApplicationInfo(ApplicationInfo ai, PackageManager pm) { String donorPackageName = null; if (ai.metaData != null) { donorPackageName = ai.metaData.getString("com.android.webview.WebViewDonorPackage"); } if (donorPackageName != null) { PackageInfo donorPackage; try { donorPackage = pm.getPackageInfo( donorPackageName, PackageManager.GET_SHARED_LIBRARY_FILES | PackageManager.MATCH_DEBUG_TRIAGED_MISSING | PackageManager.MATCH_UNINSTALLED_PACKAGES | PackageManager.MATCH_FACTORY_ONLY); } catch (PackageManager.NameNotFoundException e) { throw new MissingWebViewPackageException("Failed to find donor package: " + donorPackageName); } ApplicationInfo donorInfo = donorPackage.applicationInfo; // Replace the stub's code locations with the donor's. ai.sourceDir = donorInfo.sourceDir; ai.splitSourceDirs = donorInfo.splitSourceDirs; ai.nativeLibraryDir = donorInfo.nativeLibraryDir; ai.secondaryNativeLibraryDir = donorInfo.secondaryNativeLibraryDir; // Copy the donor's primary and secondary ABIs, since the stub doesn't have native code // and so they are unset. ai.primaryCpuAbi = donorInfo.primaryCpuAbi; ai.secondaryCpuAbi = donorInfo.secondaryCpuAbi; } } private static Context getWebViewContextAndSetProvider() { Application initialApplication = AppGlobals.getInitialApplication(); try { Loading Loading @@ -307,9 +345,10 @@ public final class WebViewFactory { } // Fetch package info and verify it against the chosen package PackageInfo newPackageInfo = null; PackageManager pm = initialApplication.getPackageManager(); Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "PackageManager.getPackageInfo()"); try { newPackageInfo = initialApplication.getPackageManager().getPackageInfo( newPackageInfo = pm.getPackageInfo( response.packageInfo.packageName, PackageManager.GET_SHARED_LIBRARY_FILES | PackageManager.MATCH_DEBUG_TRIAGED_MISSING Loading @@ -328,12 +367,15 @@ public final class WebViewFactory { // failure verifyPackageInfo(response.packageInfo, newPackageInfo); ApplicationInfo ai = newPackageInfo.applicationInfo; fixupStubApplicationInfo(ai, pm); Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "initialApplication.createApplicationContext"); try { // Construct an app context to load the Java code into the current app. Context webViewContext = initialApplication.createApplicationContext( newPackageInfo.applicationInfo, ai, Context.CONTEXT_INCLUDE_CODE | Context.CONTEXT_IGNORE_SECURITY); sPackageInfo = newPackageInfo; return webViewContext; Loading Loading @@ -449,7 +491,11 @@ public final class WebViewFactory { */ public static int onWebViewProviderChanged(PackageInfo packageInfo) { String[] nativeLibs = null; String originalSourceDir = packageInfo.applicationInfo.sourceDir; try { fixupStubApplicationInfo(packageInfo.applicationInfo, AppGlobals.getInitialApplication().getPackageManager()); nativeLibs = WebViewFactory.getWebViewNativeLibraryPaths(packageInfo); if (nativeLibs != null) { long newVmSize = 0L; Loading Loading @@ -498,7 +544,7 @@ public final class WebViewFactory { Log.e(LOGTAG, "error preparing webview native library", t); } WebViewZygote.onWebViewProviderChanged(packageInfo); WebViewZygote.onWebViewProviderChanged(packageInfo, originalSourceDir); return prepareWebViewInSystemServer(nativeLibs); } Loading core/java/android/webkit/WebViewZygote.java +11 −2 Original line number Diff line number Diff line Loading @@ -66,6 +66,13 @@ public class WebViewZygote { @GuardedBy("sLock") private static PackageInfo sPackage; /** * Cache key for the selected WebView package's classloader. This is set from * #onWebViewProviderChanged(). */ @GuardedBy("sLock") private static String sPackageCacheKey; /** * Flag for whether multi-process WebView is enabled. If this is false, the zygote * will not be started. Loading Loading @@ -118,9 +125,10 @@ public class WebViewZygote { } } public static void onWebViewProviderChanged(PackageInfo packageInfo) { public static void onWebViewProviderChanged(PackageInfo packageInfo, String cacheKey) { synchronized (sLock) { sPackage = packageInfo; sPackageCacheKey = cacheKey; // If multi-process is not enabled, then do not start the zygote service. if (!sMultiprocessEnabled) { Loading Loading @@ -210,7 +218,8 @@ public class WebViewZygote { TextUtils.join(File.pathSeparator, zipPaths); Log.d(LOGTAG, "Preloading package " + zip + " " + librarySearchPath); sZygote.preloadPackageForAbi(zip, librarySearchPath, Build.SUPPORTED_ABIS[0]); sZygote.preloadPackageForAbi(zip, librarySearchPath, sPackageCacheKey, 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 +8 −3 Original line number Diff line number Diff line Loading @@ -26,6 +26,7 @@ import android.util.Log; import android.webkit.WebViewFactory; import android.webkit.WebViewFactoryProvider; import java.io.File; import java.io.IOException; import java.lang.reflect.InvocationTargetException; Loading Loading @@ -67,16 +68,20 @@ class WebViewZygoteInit { } @Override protected boolean handlePreloadPackage(String packagePath, String libsPath) { protected boolean handlePreloadPackage(String packagePath, String libsPath, String cacheKey) { // 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); packagePath, libsPath, cacheKey); // Add the APK to the Zygote's list of allowed files for children. Zygote.nativeAllowFileAcrossFork(packagePath); String[] packageList = TextUtils.split(packagePath, File.pathSeparator); for (String packageEntry : packageList) { Zygote.nativeAllowFileAcrossFork(packageEntry); } // 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 Loading Loading
core/java/android/app/ApplicationLoaders.java +23 −10 Original line number Diff line number Diff line Loading @@ -18,6 +18,7 @@ package android.app; import android.os.Build; import android.os.Trace; import android.text.TextUtils; import android.util.ArrayMap; import com.android.internal.os.PathClassLoaderFactory; import dalvik.system.PathClassLoader; Loading @@ -31,6 +32,14 @@ public class ApplicationLoaders { ClassLoader getClassLoader(String zip, int targetSdkVersion, boolean isBundled, String librarySearchPath, String libraryPermittedPath, ClassLoader parent) { // For normal usage the cache key used is the same as the zip path. return getClassLoader(zip, targetSdkVersion, isBundled, librarySearchPath, libraryPermittedPath, parent, zip); } private ClassLoader getClassLoader(String zip, int targetSdkVersion, boolean isBundled, String librarySearchPath, String libraryPermittedPath, ClassLoader parent, String cacheKey) { /* * This is the parent we use if they pass "null" in. In theory * this should be the "system" class loader; in practice we Loading @@ -50,7 +59,7 @@ public class ApplicationLoaders { * new ClassLoader for the zip archive. */ if (parent == baseParent) { ClassLoader loader = mLoaders.get(zip); ClassLoader loader = mLoaders.get(cacheKey); if (loader != null) { return loader; } Loading @@ -71,7 +80,7 @@ public class ApplicationLoaders { setupVulkanLayerPath(pathClassloader, librarySearchPath); Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER); mLoaders.put(zip, pathClassloader); mLoaders.put(cacheKey, pathClassloader); return pathClassloader; } Loading @@ -87,12 +96,16 @@ public class ApplicationLoaders { * 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) { public ClassLoader createAndCacheWebViewClassLoader(String packagePath, String libsPath, String cacheKey) { // 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); // The cache key is passed separately to enable the stub WebView to be cached under the // stub's APK path, when the actual package path is the donor APK. return getClassLoader(packagePath, Build.VERSION.SDK_INT, false, libsPath, null, null, cacheKey); } private static native void setupVulkanLayerPath(ClassLoader classLoader, String librarySearchPath); Loading
core/java/android/os/ZygoteProcess.java +6 −3 Original line number Diff line number Diff line Loading @@ -487,11 +487,11 @@ public class ZygoteProcess { * Instructs the zygote to pre-load the classes and native libraries at the given paths * for the specified abi. Not all zygotes support this function. */ public void preloadPackageForAbi(String packagePath, String libsPath, String abi) throws ZygoteStartFailedEx, IOException { public void preloadPackageForAbi(String packagePath, String libsPath, String cacheKey, String abi) throws ZygoteStartFailedEx, IOException { synchronized(mLock) { ZygoteState state = openZygoteSocketIfNeeded(abi); state.writer.write("3"); state.writer.write("4"); state.writer.newLine(); state.writer.write("--preload-package"); Loading @@ -503,6 +503,9 @@ public class ZygoteProcess { state.writer.write(libsPath); state.writer.newLine(); state.writer.write(cacheKey); state.writer.newLine(); state.writer.flush(); } } Loading
core/java/android/webkit/WebViewFactory.java +49 −3 Original line number Diff line number Diff line Loading @@ -280,6 +280,44 @@ public final class WebViewFactory { } } /** * If the ApplicationInfo provided is for a stub WebView, fix up the object to include the * required values from the donor package. If the ApplicationInfo is for a full WebView, * leave it alone. Throws MissingWebViewPackageException if the donor is missing. */ private static void fixupStubApplicationInfo(ApplicationInfo ai, PackageManager pm) { String donorPackageName = null; if (ai.metaData != null) { donorPackageName = ai.metaData.getString("com.android.webview.WebViewDonorPackage"); } if (donorPackageName != null) { PackageInfo donorPackage; try { donorPackage = pm.getPackageInfo( donorPackageName, PackageManager.GET_SHARED_LIBRARY_FILES | PackageManager.MATCH_DEBUG_TRIAGED_MISSING | PackageManager.MATCH_UNINSTALLED_PACKAGES | PackageManager.MATCH_FACTORY_ONLY); } catch (PackageManager.NameNotFoundException e) { throw new MissingWebViewPackageException("Failed to find donor package: " + donorPackageName); } ApplicationInfo donorInfo = donorPackage.applicationInfo; // Replace the stub's code locations with the donor's. ai.sourceDir = donorInfo.sourceDir; ai.splitSourceDirs = donorInfo.splitSourceDirs; ai.nativeLibraryDir = donorInfo.nativeLibraryDir; ai.secondaryNativeLibraryDir = donorInfo.secondaryNativeLibraryDir; // Copy the donor's primary and secondary ABIs, since the stub doesn't have native code // and so they are unset. ai.primaryCpuAbi = donorInfo.primaryCpuAbi; ai.secondaryCpuAbi = donorInfo.secondaryCpuAbi; } } private static Context getWebViewContextAndSetProvider() { Application initialApplication = AppGlobals.getInitialApplication(); try { Loading Loading @@ -307,9 +345,10 @@ public final class WebViewFactory { } // Fetch package info and verify it against the chosen package PackageInfo newPackageInfo = null; PackageManager pm = initialApplication.getPackageManager(); Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "PackageManager.getPackageInfo()"); try { newPackageInfo = initialApplication.getPackageManager().getPackageInfo( newPackageInfo = pm.getPackageInfo( response.packageInfo.packageName, PackageManager.GET_SHARED_LIBRARY_FILES | PackageManager.MATCH_DEBUG_TRIAGED_MISSING Loading @@ -328,12 +367,15 @@ public final class WebViewFactory { // failure verifyPackageInfo(response.packageInfo, newPackageInfo); ApplicationInfo ai = newPackageInfo.applicationInfo; fixupStubApplicationInfo(ai, pm); Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "initialApplication.createApplicationContext"); try { // Construct an app context to load the Java code into the current app. Context webViewContext = initialApplication.createApplicationContext( newPackageInfo.applicationInfo, ai, Context.CONTEXT_INCLUDE_CODE | Context.CONTEXT_IGNORE_SECURITY); sPackageInfo = newPackageInfo; return webViewContext; Loading Loading @@ -449,7 +491,11 @@ public final class WebViewFactory { */ public static int onWebViewProviderChanged(PackageInfo packageInfo) { String[] nativeLibs = null; String originalSourceDir = packageInfo.applicationInfo.sourceDir; try { fixupStubApplicationInfo(packageInfo.applicationInfo, AppGlobals.getInitialApplication().getPackageManager()); nativeLibs = WebViewFactory.getWebViewNativeLibraryPaths(packageInfo); if (nativeLibs != null) { long newVmSize = 0L; Loading Loading @@ -498,7 +544,7 @@ public final class WebViewFactory { Log.e(LOGTAG, "error preparing webview native library", t); } WebViewZygote.onWebViewProviderChanged(packageInfo); WebViewZygote.onWebViewProviderChanged(packageInfo, originalSourceDir); return prepareWebViewInSystemServer(nativeLibs); } Loading
core/java/android/webkit/WebViewZygote.java +11 −2 Original line number Diff line number Diff line Loading @@ -66,6 +66,13 @@ public class WebViewZygote { @GuardedBy("sLock") private static PackageInfo sPackage; /** * Cache key for the selected WebView package's classloader. This is set from * #onWebViewProviderChanged(). */ @GuardedBy("sLock") private static String sPackageCacheKey; /** * Flag for whether multi-process WebView is enabled. If this is false, the zygote * will not be started. Loading Loading @@ -118,9 +125,10 @@ public class WebViewZygote { } } public static void onWebViewProviderChanged(PackageInfo packageInfo) { public static void onWebViewProviderChanged(PackageInfo packageInfo, String cacheKey) { synchronized (sLock) { sPackage = packageInfo; sPackageCacheKey = cacheKey; // If multi-process is not enabled, then do not start the zygote service. if (!sMultiprocessEnabled) { Loading Loading @@ -210,7 +218,8 @@ public class WebViewZygote { TextUtils.join(File.pathSeparator, zipPaths); Log.d(LOGTAG, "Preloading package " + zip + " " + librarySearchPath); sZygote.preloadPackageForAbi(zip, librarySearchPath, Build.SUPPORTED_ABIS[0]); sZygote.preloadPackageForAbi(zip, librarySearchPath, sPackageCacheKey, 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 +8 −3 Original line number Diff line number Diff line Loading @@ -26,6 +26,7 @@ import android.util.Log; import android.webkit.WebViewFactory; import android.webkit.WebViewFactoryProvider; import java.io.File; import java.io.IOException; import java.lang.reflect.InvocationTargetException; Loading Loading @@ -67,16 +68,20 @@ class WebViewZygoteInit { } @Override protected boolean handlePreloadPackage(String packagePath, String libsPath) { protected boolean handlePreloadPackage(String packagePath, String libsPath, String cacheKey) { // 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); packagePath, libsPath, cacheKey); // Add the APK to the Zygote's list of allowed files for children. Zygote.nativeAllowFileAcrossFork(packagePath); String[] packageList = TextUtils.split(packagePath, File.pathSeparator); for (String packageEntry : packageList) { Zygote.nativeAllowFileAcrossFork(packageEntry); } // 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 Loading