summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Torne (Richard Coles) <torne@google.com> 2019-01-14 15:58:39 -0500
committer Torne (Richard Coles) <torne@google.com> 2019-01-23 14:25:44 -0500
commite032061ddb59cd4cbcefa94eecab0e140e7556f4 (patch)
tree2e52781e474bc24614fa86a80e1b2130c53dae5e
parent070aba8e540928338a893755158a239b8e146bae (diff)
Use new app preload path for WebView zygote.
In the "common" case where the WebView stub is not being used, have the WebView zygote use the new APK preload path added for the app zygote, which avoids duplicating logic from the framework to construct the classpath. This allows the WebView implementation to use a static shared library, which was not previously possible. The old codepath is retained for now to keep the WebView stub working when it's in use, as it requires the special mechanism to override the classloader cache key, but this can be removed when we no longer require the stub. Bug: 110790153 Test: Manual verification of classloader cache state Change-Id: Ie49e5810d570bae7bec0341753e6c50d081189b5
-rw-r--r--core/java/android/webkit/WebViewZygote.java56
-rw-r--r--core/java/com/android/internal/os/WebViewZygoteInit.java47
2 files changed, 69 insertions, 34 deletions
diff --git a/core/java/android/webkit/WebViewZygote.java b/core/java/android/webkit/WebViewZygote.java
index 3a1c4576ab3e..de1f3df61462 100644
--- a/core/java/android/webkit/WebViewZygote.java
+++ b/core/java/android/webkit/WebViewZygote.java
@@ -150,6 +150,7 @@ public class WebViewZygote {
}
try {
+ String abi = sPackage.applicationInfo.primaryCpuAbi;
sZygote = Process.ZYGOTE_PROCESS.startChildZygote(
"com.android.internal.os.WebViewZygoteInit",
"webview_zygote",
@@ -158,39 +159,40 @@ public class WebViewZygote {
null, // gids
0, // runtimeFlags
"webview_zygote", // seInfo
- sPackage.applicationInfo.primaryCpuAbi, // abi
+ abi, // abi
TextUtils.join(",", Build.SUPPORTED_ABIS),
null, // instructionSet
Process.FIRST_ISOLATED_UID,
Process.LAST_ISOLATED_UID);
-
- // 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, false, 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);
-
- String libFileName = WebViewFactory.getWebViewLibrary(sPackage.applicationInfo);
-
- // In the case where the ApplicationInfo has been modified by the stub WebView,
- // we need to use the original ApplicationInfo to determine what the original classpath
- // would have been to use as a cache key.
- LoadedApk.makePaths(null, false, sPackageOriginalAppInfo, zipPaths, null);
- final String cacheKey = (zipPaths.size() == 1) ? zipPaths.get(0) :
- TextUtils.join(File.pathSeparator, zipPaths);
-
ZygoteProcess.waitForConnectionToZygote(sZygote.getPrimarySocketAddress());
- Log.d(LOGTAG, "Preloading package " + zip + " " + librarySearchPath);
- sZygote.preloadPackageForAbi(zip, librarySearchPath, libFileName, cacheKey,
- Build.SUPPORTED_ABIS[0]);
+ if (sPackageOriginalAppInfo.sourceDir.equals(sPackage.applicationInfo.sourceDir)) {
+ // No stub WebView is involved here, so we can preload the package the "clean" way
+ // using the ApplicationInfo.
+ sZygote.preloadApp(sPackage.applicationInfo, abi);
+ } else {
+ // Legacy path to support the stub WebView.
+ // 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, false, 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);
+
+ String libFileName = WebViewFactory.getWebViewLibrary(sPackage.applicationInfo);
+
+ // Use the original ApplicationInfo to determine what the original classpath would
+ // have been to use as a cache key.
+ LoadedApk.makePaths(null, false, sPackageOriginalAppInfo, zipPaths, null);
+ final String cacheKey = (zipPaths.size() == 1) ? zipPaths.get(0) :
+ TextUtils.join(File.pathSeparator, zipPaths);
+
+ Log.d(LOGTAG, "Preloading package " + zip + " " + librarySearchPath);
+ sZygote.preloadPackageForAbi(zip, librarySearchPath, libFileName, cacheKey,
+ Build.SUPPORTED_ABIS[0]);
+ }
} catch (Exception e) {
Log.e(LOGTAG, "Error connecting to webview zygote", e);
stopZygoteLocked();
diff --git a/core/java/com/android/internal/os/WebViewZygoteInit.java b/core/java/com/android/internal/os/WebViewZygoteInit.java
index 0b329d70f7af..c8d30b27d4dc 100644
--- a/core/java/com/android/internal/os/WebViewZygoteInit.java
+++ b/core/java/com/android/internal/os/WebViewZygoteInit.java
@@ -17,8 +17,9 @@
package com.android.internal.os;
import android.app.ApplicationLoaders;
+import android.app.LoadedApk;
+import android.content.pm.ApplicationInfo;
import android.net.LocalSocket;
-import android.os.Build;
import android.text.TextUtils;
import android.util.Log;
import android.webkit.WebViewFactory;
@@ -66,6 +67,34 @@ class WebViewZygoteInit {
}
@Override
+ protected boolean canPreloadApp() {
+ return true;
+ }
+
+ @Override
+ protected void handlePreloadApp(ApplicationInfo appInfo) {
+ Log.i(TAG, "Beginning application preload for " + appInfo.packageName);
+ LoadedApk loadedApk = new LoadedApk(null, appInfo, null, null, false, true, false);
+ ClassLoader loader = loadedApk.getClassLoader();
+ doPreload(loader, WebViewFactory.getWebViewLibrary(appInfo));
+
+ // Add the APK to the Zygote's list of allowed files for children.
+ Zygote.nativeAllowFileAcrossFork(appInfo.sourceDir);
+ if (appInfo.splitSourceDirs != null) {
+ for (String path : appInfo.splitSourceDirs) {
+ Zygote.nativeAllowFileAcrossFork(path);
+ }
+ }
+ if (appInfo.sharedLibraryFiles != null) {
+ for (String path : appInfo.sharedLibraryFiles) {
+ Zygote.nativeAllowFileAcrossFork(path);
+ }
+ }
+
+ Log.i(TAG, "Application preload done");
+ }
+
+ @Override
protected void handlePreloadPackage(String packagePath, String libsPath, String libFileName,
String cacheKey) {
Log.i(TAG, "Beginning package preload");
@@ -76,16 +105,22 @@ class WebViewZygoteInit {
ClassLoader loader = ApplicationLoaders.getDefault().createAndCacheWebViewClassLoader(
packagePath, libsPath, cacheKey);
- // Load the native library using WebViewLibraryLoader to share the RELRO data with other
- // processes.
- WebViewLibraryLoader.loadNativeLibrary(loader, libFileName);
-
// Add the APK to the Zygote's list of allowed files for children.
String[] packageList = TextUtils.split(packagePath, File.pathSeparator);
for (String packageEntry : packageList) {
Zygote.nativeAllowFileAcrossFork(packageEntry);
}
+ doPreload(loader, libFileName);
+
+ Log.i(TAG, "Package preload done");
+ }
+
+ private void doPreload(ClassLoader loader, String libFileName) {
+ // Load the native library using WebViewLibraryLoader to share the RELRO data with other
+ // processes.
+ WebViewLibraryLoader.loadNativeLibrary(loader, libFileName);
+
// 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.
@@ -114,8 +149,6 @@ class WebViewZygoteInit {
} catch (IOException ioe) {
throw new IllegalStateException("Error writing to command socket", ioe);
}
-
- Log.i(TAG, "Package preload done");
}
}