diff options
| author | TreeHugger Robot <treehugger-gerrit@google.com> | 2017-03-28 17:11:21 +0000 |
|---|---|---|
| committer | Android (Google) Code Review <android-gerrit@google.com> | 2017-03-28 17:11:26 +0000 |
| commit | 7ec7ef2ba3403c0499e17b96a788e7594d60df2d (patch) | |
| tree | c5f14736fb51529e467dd8975f0430d755ac9882 /core/java/android | |
| parent | dedfcaf539eea2a762aa8730e231906edd2e1be2 (diff) | |
| parent | 0452670374ebb2a22d2dc44c030f7b43173800c0 (diff) | |
Merge "Support loading a stub WebView using a donor package." into oc-dev
Diffstat (limited to 'core/java/android')
| -rw-r--r-- | core/java/android/app/ApplicationLoaders.java | 33 | ||||
| -rw-r--r-- | core/java/android/os/ZygoteProcess.java | 9 | ||||
| -rw-r--r-- | core/java/android/webkit/WebViewFactory.java | 52 | ||||
| -rw-r--r-- | core/java/android/webkit/WebViewZygote.java | 13 |
4 files changed, 89 insertions, 18 deletions
diff --git a/core/java/android/app/ApplicationLoaders.java b/core/java/android/app/ApplicationLoaders.java index ef2db4a0d795..2062930929a2 100644 --- a/core/java/android/app/ApplicationLoaders.java +++ b/core/java/android/app/ApplicationLoaders.java @@ -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; @@ -29,8 +30,16 @@ public class ApplicationLoaders { } ClassLoader getClassLoader(String zip, int targetSdkVersion, boolean isBundled, - String librarySearchPath, String libraryPermittedPath, - ClassLoader parent) { + 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 @@ -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; } @@ -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; } @@ -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) { - // 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); + 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. + // 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); diff --git a/core/java/android/os/ZygoteProcess.java b/core/java/android/os/ZygoteProcess.java index b3366d883fc6..8208438dc62a 100644 --- a/core/java/android/os/ZygoteProcess.java +++ b/core/java/android/os/ZygoteProcess.java @@ -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"); @@ -503,6 +503,9 @@ public class ZygoteProcess { state.writer.write(libsPath); state.writer.newLine(); + state.writer.write(cacheKey); + state.writer.newLine(); + state.writer.flush(); } } diff --git a/core/java/android/webkit/WebViewFactory.java b/core/java/android/webkit/WebViewFactory.java index 81c2f5d5ef4c..71db6b141ca9 100644 --- a/core/java/android/webkit/WebViewFactory.java +++ b/core/java/android/webkit/WebViewFactory.java @@ -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 { @@ -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 @@ -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; @@ -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; @@ -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); } diff --git a/core/java/android/webkit/WebViewZygote.java b/core/java/android/webkit/WebViewZygote.java index f78d62250029..2123debfeb67 100644 --- a/core/java/android/webkit/WebViewZygote.java +++ b/core/java/android/webkit/WebViewZygote.java @@ -67,6 +67,13 @@ public class WebViewZygote { 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. */ @@ -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) { @@ -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; |
