1ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton/* 2ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton * Copyright (C) 2017 The Android Open Source Project 3ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton * 4ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton * Licensed under the Apache License, Version 2.0 (the "License"); 5ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton * you may not use this file except in compliance with the License. 6ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton * You may obtain a copy of the License at 7ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton * 8ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton * http://www.apache.org/licenses/LICENSE-2.0 9ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton * 10ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton * Unless required by applicable law or agreed to in writing, software 11ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton * distributed under the License is distributed on an "AS IS" BASIS, 12ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton * See the License for the specific language governing permissions and 14ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton * limitations under the License. 15ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton */ 16ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton 17ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Senntonpackage android.webkit; 18ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton 1936bed13f8340359fac1c709460cfa95142c5e6a1Gustav Senntonimport android.annotation.NonNull; 2036bed13f8340359fac1c709460cfa95142c5e6a1Gustav Senntonimport android.annotation.Nullable; 21ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Senntonimport android.app.ActivityManagerInternal; 22ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Senntonimport android.content.pm.ApplicationInfo; 23ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Senntonimport android.content.pm.PackageInfo; 24ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Senntonimport android.os.Build; 25ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Senntonimport android.os.Process; 26ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Senntonimport android.os.RemoteException; 27ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Senntonimport android.os.SystemProperties; 28ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Senntonimport android.text.TextUtils; 29ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Senntonimport android.util.Log; 30ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton 3136bed13f8340359fac1c709460cfa95142c5e6a1Gustav Senntonimport com.android.internal.annotations.VisibleForTesting; 32ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Senntonimport com.android.server.LocalServices; 33ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton 34ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Senntonimport dalvik.system.VMRuntime; 35ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton 36ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Senntonimport java.io.File; 37ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Senntonimport java.io.IOException; 38ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Senntonimport java.util.Arrays; 39ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Senntonimport java.util.zip.ZipEntry; 40ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Senntonimport java.util.zip.ZipFile; 41ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton 4236bed13f8340359fac1c709460cfa95142c5e6a1Gustav Sennton/** 4336bed13f8340359fac1c709460cfa95142c5e6a1Gustav Sennton * @hide 4436bed13f8340359fac1c709460cfa95142c5e6a1Gustav Sennton */ 4536bed13f8340359fac1c709460cfa95142c5e6a1Gustav Sennton@VisibleForTesting 4636bed13f8340359fac1c709460cfa95142c5e6a1Gustav Senntonpublic class WebViewLibraryLoader { 47ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton private static final String LOGTAG = WebViewLibraryLoader.class.getSimpleName(); 48ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton 49ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton private static final String CHROMIUM_WEBVIEW_NATIVE_RELRO_32 = 50ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton "/data/misc/shared_relro/libwebviewchromium32.relro"; 51ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton private static final String CHROMIUM_WEBVIEW_NATIVE_RELRO_64 = 52ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton "/data/misc/shared_relro/libwebviewchromium64.relro"; 53ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton private static final long CHROMIUM_WEBVIEW_DEFAULT_VMSIZE_BYTES = 100 * 1024 * 1024; 54ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton 55ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton private static final boolean DEBUG = false; 56ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton 57ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton private static boolean sAddressSpaceReserved = false; 58ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton 59ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton /** 60ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton * Private class for running the actual relro creation in an unprivileged child process. 61ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton * RelroFileCreator is a static class (without access to the outer class) to avoid accidentally 62ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton * using any static members from the outer class. Those members will in reality differ between 63ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton * the child process in which RelroFileCreator operates, and the app process in which the static 64ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton * members of this class are used. 65ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton */ 66ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton private static class RelroFileCreator { 67ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton // Called in an unprivileged child process to create the relro file. 68ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton public static void main(String[] args) { 69ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton boolean result = false; 70ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton boolean is64Bit = VMRuntime.getRuntime().is64Bit(); 71ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton try { 72ae498f270230e20b5a777ed2d6387a21767625a3Gustav Sennton if (args.length != 1 || args[0] == null) { 73ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton Log.e(LOGTAG, "Invalid RelroFileCreator args: " + Arrays.toString(args)); 74ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton return; 75ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton } 76ae498f270230e20b5a777ed2d6387a21767625a3Gustav Sennton Log.v(LOGTAG, "RelroFileCreator (64bit = " + is64Bit + "), lib: " + args[0]); 77ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton if (!sAddressSpaceReserved) { 78ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton Log.e(LOGTAG, "can't create relro file; address space not reserved"); 79ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton return; 80ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton } 81ae498f270230e20b5a777ed2d6387a21767625a3Gustav Sennton result = nativeCreateRelroFile(args[0] /* path */, 82ae498f270230e20b5a777ed2d6387a21767625a3Gustav Sennton is64Bit ? CHROMIUM_WEBVIEW_NATIVE_RELRO_64 : 83ae498f270230e20b5a777ed2d6387a21767625a3Gustav Sennton CHROMIUM_WEBVIEW_NATIVE_RELRO_32); 84ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton if (result && DEBUG) Log.v(LOGTAG, "created relro file"); 85ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton } finally { 86ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton // We must do our best to always notify the update service, even if something fails. 87ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton try { 8829675b294126bd00bb51bc8616f476aa90abacf1Torne (Richard Coles) WebViewFactory.getUpdateServiceUnchecked().notifyRelroCreationCompleted(); 89ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton } catch (RemoteException e) { 90ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton Log.e(LOGTAG, "error notifying update service", e); 91ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton } 92ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton 93ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton if (!result) Log.e(LOGTAG, "failed to create relro file"); 94ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton 95ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton // Must explicitly exit or else this process will just sit around after we return. 96ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton System.exit(0); 97ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton } 98ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton } 99ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton } 100ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton 101ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton /** 102ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton * Create a single relro file by invoking an isolated process that to do the actual work. 103ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton */ 10436bed13f8340359fac1c709460cfa95142c5e6a1Gustav Sennton static void createRelroFile(final boolean is64Bit, @NonNull WebViewNativeLibrary nativeLib) { 105ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton final String abi = 106ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton is64Bit ? Build.SUPPORTED_64_BIT_ABIS[0] : Build.SUPPORTED_32_BIT_ABIS[0]; 107ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton 108ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton // crashHandler is invoked by the ActivityManagerService when the isolated process crashes. 109ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton Runnable crashHandler = new Runnable() { 110ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton @Override 111ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton public void run() { 112ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton try { 113ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton Log.e(LOGTAG, "relro file creator for " + abi + " crashed. Proceeding without"); 114ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton WebViewFactory.getUpdateService().notifyRelroCreationCompleted(); 115ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton } catch (RemoteException e) { 116ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton Log.e(LOGTAG, "Cannot reach WebViewUpdateService. " + e.getMessage()); 117ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton } 118ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton } 119ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton }; 120ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton 121ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton try { 12236bed13f8340359fac1c709460cfa95142c5e6a1Gustav Sennton if (nativeLib == null || nativeLib.path == null) { 123ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton throw new IllegalArgumentException( 124ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton "Native library paths to the WebView RelRo process must not be null!"); 125ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton } 126f6690100be5c5cd75c64d9a6a0345acff7b754d1Sudheer Shanka boolean success = LocalServices.getService(ActivityManagerInternal.class) 127f6690100be5c5cd75c64d9a6a0345acff7b754d1Sudheer Shanka .startIsolatedProcess( 128f6690100be5c5cd75c64d9a6a0345acff7b754d1Sudheer Shanka RelroFileCreator.class.getName(), new String[] { nativeLib.path }, 129f6690100be5c5cd75c64d9a6a0345acff7b754d1Sudheer Shanka "WebViewLoader-" + abi, abi, Process.SHARED_RELRO_UID, crashHandler); 130f6690100be5c5cd75c64d9a6a0345acff7b754d1Sudheer Shanka if (!success) throw new Exception("Failed to start the relro file creator process"); 131ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton } catch (Throwable t) { 132ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton // Log and discard errors as we must not crash the system server. 133ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton Log.e(LOGTAG, "error starting relro file creator for abi " + abi, t); 134ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton crashHandler.run(); 135ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton } 136ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton } 137ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton 13836bed13f8340359fac1c709460cfa95142c5e6a1Gustav Sennton /** 13936bed13f8340359fac1c709460cfa95142c5e6a1Gustav Sennton * Perform preparations needed to allow loading WebView from an application. This method should 14036bed13f8340359fac1c709460cfa95142c5e6a1Gustav Sennton * be called whenever we change WebView provider. 14136bed13f8340359fac1c709460cfa95142c5e6a1Gustav Sennton * @return the number of relro processes started. 14236bed13f8340359fac1c709460cfa95142c5e6a1Gustav Sennton */ 1430e541ef99221d7681e2fe0d721e92c4d6c74073cGustav Sennton static int prepareNativeLibraries(PackageInfo webviewPackageInfo) 1440e541ef99221d7681e2fe0d721e92c4d6c74073cGustav Sennton throws WebViewFactory.MissingWebViewPackageException { 14536bed13f8340359fac1c709460cfa95142c5e6a1Gustav Sennton WebViewNativeLibrary nativeLib32bit = 14636bed13f8340359fac1c709460cfa95142c5e6a1Gustav Sennton getWebViewNativeLibrary(webviewPackageInfo, false /* is64bit */); 14736bed13f8340359fac1c709460cfa95142c5e6a1Gustav Sennton WebViewNativeLibrary nativeLib64bit = 14836bed13f8340359fac1c709460cfa95142c5e6a1Gustav Sennton getWebViewNativeLibrary(webviewPackageInfo, true /* is64bit */); 14936bed13f8340359fac1c709460cfa95142c5e6a1Gustav Sennton updateWebViewZygoteVmSize(nativeLib32bit, nativeLib64bit); 15036bed13f8340359fac1c709460cfa95142c5e6a1Gustav Sennton 15136bed13f8340359fac1c709460cfa95142c5e6a1Gustav Sennton return createRelros(nativeLib32bit, nativeLib64bit); 15236bed13f8340359fac1c709460cfa95142c5e6a1Gustav Sennton } 15336bed13f8340359fac1c709460cfa95142c5e6a1Gustav Sennton 15436bed13f8340359fac1c709460cfa95142c5e6a1Gustav Sennton /** 15536bed13f8340359fac1c709460cfa95142c5e6a1Gustav Sennton * @return the number of relro processes started. 15636bed13f8340359fac1c709460cfa95142c5e6a1Gustav Sennton */ 15736bed13f8340359fac1c709460cfa95142c5e6a1Gustav Sennton private static int createRelros(@Nullable WebViewNativeLibrary nativeLib32bit, 15836bed13f8340359fac1c709460cfa95142c5e6a1Gustav Sennton @Nullable WebViewNativeLibrary nativeLib64bit) { 1590e541ef99221d7681e2fe0d721e92c4d6c74073cGustav Sennton if (DEBUG) Log.v(LOGTAG, "creating relro files"); 1600e541ef99221d7681e2fe0d721e92c4d6c74073cGustav Sennton int numRelros = 0; 1610e541ef99221d7681e2fe0d721e92c4d6c74073cGustav Sennton 1620e541ef99221d7681e2fe0d721e92c4d6c74073cGustav Sennton if (Build.SUPPORTED_32_BIT_ABIS.length > 0) { 16336bed13f8340359fac1c709460cfa95142c5e6a1Gustav Sennton if (nativeLib32bit == null) { 16436bed13f8340359fac1c709460cfa95142c5e6a1Gustav Sennton Log.e(LOGTAG, "No 32-bit WebView library path, skipping relro creation."); 16536bed13f8340359fac1c709460cfa95142c5e6a1Gustav Sennton } else { 16636bed13f8340359fac1c709460cfa95142c5e6a1Gustav Sennton if (DEBUG) Log.v(LOGTAG, "Create 32 bit relro"); 16736bed13f8340359fac1c709460cfa95142c5e6a1Gustav Sennton createRelroFile(false /* is64Bit */, nativeLib32bit); 16836bed13f8340359fac1c709460cfa95142c5e6a1Gustav Sennton numRelros++; 16936bed13f8340359fac1c709460cfa95142c5e6a1Gustav Sennton } 1700e541ef99221d7681e2fe0d721e92c4d6c74073cGustav Sennton } 1710e541ef99221d7681e2fe0d721e92c4d6c74073cGustav Sennton 1720e541ef99221d7681e2fe0d721e92c4d6c74073cGustav Sennton if (Build.SUPPORTED_64_BIT_ABIS.length > 0) { 17336bed13f8340359fac1c709460cfa95142c5e6a1Gustav Sennton if (nativeLib64bit == null) { 17436bed13f8340359fac1c709460cfa95142c5e6a1Gustav Sennton Log.e(LOGTAG, "No 64-bit WebView library path, skipping relro creation."); 17536bed13f8340359fac1c709460cfa95142c5e6a1Gustav Sennton } else { 17636bed13f8340359fac1c709460cfa95142c5e6a1Gustav Sennton if (DEBUG) Log.v(LOGTAG, "Create 64 bit relro"); 17736bed13f8340359fac1c709460cfa95142c5e6a1Gustav Sennton createRelroFile(true /* is64Bit */, nativeLib64bit); 17836bed13f8340359fac1c709460cfa95142c5e6a1Gustav Sennton numRelros++; 17936bed13f8340359fac1c709460cfa95142c5e6a1Gustav Sennton } 1800e541ef99221d7681e2fe0d721e92c4d6c74073cGustav Sennton } 1810e541ef99221d7681e2fe0d721e92c4d6c74073cGustav Sennton return numRelros; 1820e541ef99221d7681e2fe0d721e92c4d6c74073cGustav Sennton } 1830e541ef99221d7681e2fe0d721e92c4d6c74073cGustav Sennton 184ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton /** 185ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton * 186ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton * @return the native WebView libraries in the new WebView APK. 187ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton */ 18836bed13f8340359fac1c709460cfa95142c5e6a1Gustav Sennton private static void updateWebViewZygoteVmSize( 18936bed13f8340359fac1c709460cfa95142c5e6a1Gustav Sennton @Nullable WebViewNativeLibrary nativeLib32bit, 19036bed13f8340359fac1c709460cfa95142c5e6a1Gustav Sennton @Nullable WebViewNativeLibrary nativeLib64bit) 191ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton throws WebViewFactory.MissingWebViewPackageException { 192ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton // Find the native libraries of the new WebView package, to change the size of the 193ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton // memory region in the Zygote reserved for the library. 19436bed13f8340359fac1c709460cfa95142c5e6a1Gustav Sennton long newVmSize = 0L; 195ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton 19636bed13f8340359fac1c709460cfa95142c5e6a1Gustav Sennton if (nativeLib32bit != null) newVmSize = Math.max(newVmSize, nativeLib32bit.size); 19736bed13f8340359fac1c709460cfa95142c5e6a1Gustav Sennton if (nativeLib64bit != null) newVmSize = Math.max(newVmSize, nativeLib64bit.size); 19836bed13f8340359fac1c709460cfa95142c5e6a1Gustav Sennton 19936bed13f8340359fac1c709460cfa95142c5e6a1Gustav Sennton if (DEBUG) { 20036bed13f8340359fac1c709460cfa95142c5e6a1Gustav Sennton Log.v(LOGTAG, "Based on library size, need " + newVmSize 20136bed13f8340359fac1c709460cfa95142c5e6a1Gustav Sennton + " bytes of address space."); 202ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton } 20336bed13f8340359fac1c709460cfa95142c5e6a1Gustav Sennton // The required memory can be larger than the file on disk (due to .bss), and an 20436bed13f8340359fac1c709460cfa95142c5e6a1Gustav Sennton // upgraded version of the library will likely be larger, so always attempt to 20536bed13f8340359fac1c709460cfa95142c5e6a1Gustav Sennton // reserve twice as much as we think to allow for the library to grow during this 20636bed13f8340359fac1c709460cfa95142c5e6a1Gustav Sennton // boot cycle. 20736bed13f8340359fac1c709460cfa95142c5e6a1Gustav Sennton newVmSize = Math.max(2 * newVmSize, CHROMIUM_WEBVIEW_DEFAULT_VMSIZE_BYTES); 20836bed13f8340359fac1c709460cfa95142c5e6a1Gustav Sennton Log.d(LOGTAG, "Setting new address space to " + newVmSize); 20936bed13f8340359fac1c709460cfa95142c5e6a1Gustav Sennton setWebViewZygoteVmSize(newVmSize); 210ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton } 211ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton 212ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton /** 213ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton * Reserve space for the native library to be loaded into. 214ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton */ 215ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton static void reserveAddressSpaceInZygote() { 216ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton System.loadLibrary("webviewchromium_loader"); 217ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton long addressSpaceToReserve = 218ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton SystemProperties.getLong(WebViewFactory.CHROMIUM_WEBVIEW_VMSIZE_SIZE_PROPERTY, 219ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton CHROMIUM_WEBVIEW_DEFAULT_VMSIZE_BYTES); 220ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton sAddressSpaceReserved = nativeReserveAddressSpace(addressSpaceToReserve); 221ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton 222ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton if (sAddressSpaceReserved) { 223ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton if (DEBUG) { 224ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton Log.v(LOGTAG, "address space reserved: " + addressSpaceToReserve + " bytes"); 225ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton } 226ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton } else { 227ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton Log.e(LOGTAG, "reserving " + addressSpaceToReserve + " bytes of address space failed"); 228ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton } 229ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton } 230ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton 231ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton /** 232ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton * Load WebView's native library into the current process. 2337051dd1eebbbca9e3d7603821ad2b5e922f7d83bNate Fischer * 2347051dd1eebbbca9e3d7603821ad2b5e922f7d83bNate Fischer * <p class="note"><b>Note:</b> Assumes that we have waited for relro creation. 2357051dd1eebbbca9e3d7603821ad2b5e922f7d83bNate Fischer * 236ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton * @param clazzLoader class loader used to find the linker namespace to load the library into. 237ec572f6a812da3a5537e3d509954cfe484b0c799Torne (Richard Coles) * @param libraryFileName the filename of the library to load. 238ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton */ 239ec572f6a812da3a5537e3d509954cfe484b0c799Torne (Richard Coles) public static int loadNativeLibrary(ClassLoader clazzLoader, String libraryFileName) { 240ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton if (!sAddressSpaceReserved) { 241ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton Log.e(LOGTAG, "can't load with relro file; address space not reserved"); 242ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton return WebViewFactory.LIBLOAD_ADDRESS_SPACE_NOT_RESERVED; 243ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton } 244ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton 245ae498f270230e20b5a777ed2d6387a21767625a3Gustav Sennton String relroPath = VMRuntime.getRuntime().is64Bit() ? CHROMIUM_WEBVIEW_NATIVE_RELRO_64 : 246ae498f270230e20b5a777ed2d6387a21767625a3Gustav Sennton CHROMIUM_WEBVIEW_NATIVE_RELRO_32; 247ae498f270230e20b5a777ed2d6387a21767625a3Gustav Sennton int result = nativeLoadWithRelroFile(libraryFileName, relroPath, clazzLoader); 248ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton if (result != WebViewFactory.LIBLOAD_SUCCESS) { 249ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton Log.w(LOGTAG, "failed to load with relro file, proceeding without"); 250ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton } else if (DEBUG) { 251ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton Log.v(LOGTAG, "loaded with relro file"); 252ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton } 253ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton return result; 254ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton } 255ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton 256ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton /** 257ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton * Fetch WebView's native library paths from {@param packageInfo}. 25836bed13f8340359fac1c709460cfa95142c5e6a1Gustav Sennton * @hide 259ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton */ 26036bed13f8340359fac1c709460cfa95142c5e6a1Gustav Sennton @Nullable 26136bed13f8340359fac1c709460cfa95142c5e6a1Gustav Sennton @VisibleForTesting 26236bed13f8340359fac1c709460cfa95142c5e6a1Gustav Sennton public static WebViewNativeLibrary getWebViewNativeLibrary(PackageInfo packageInfo, 26336bed13f8340359fac1c709460cfa95142c5e6a1Gustav Sennton boolean is64bit) throws WebViewFactory.MissingWebViewPackageException { 264ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton ApplicationInfo ai = packageInfo.applicationInfo; 265ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton final String nativeLibFileName = WebViewFactory.getWebViewLibrary(ai); 266ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton 26736bed13f8340359fac1c709460cfa95142c5e6a1Gustav Sennton String dir = getWebViewNativeLibraryDirectory(ai, is64bit /* 64bit */); 26836bed13f8340359fac1c709460cfa95142c5e6a1Gustav Sennton 26936bed13f8340359fac1c709460cfa95142c5e6a1Gustav Sennton WebViewNativeLibrary lib = findNativeLibrary(ai, nativeLibFileName, 27036bed13f8340359fac1c709460cfa95142c5e6a1Gustav Sennton is64bit ? Build.SUPPORTED_64_BIT_ABIS : Build.SUPPORTED_32_BIT_ABIS, dir); 27136bed13f8340359fac1c709460cfa95142c5e6a1Gustav Sennton 27236bed13f8340359fac1c709460cfa95142c5e6a1Gustav Sennton if (DEBUG) { 27336bed13f8340359fac1c709460cfa95142c5e6a1Gustav Sennton Log.v(LOGTAG, String.format("Native %d-bit lib: %s", is64bit ? 64 : 32, lib.path)); 274ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton } 27536bed13f8340359fac1c709460cfa95142c5e6a1Gustav Sennton return lib; 27636bed13f8340359fac1c709460cfa95142c5e6a1Gustav Sennton } 277ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton 27836bed13f8340359fac1c709460cfa95142c5e6a1Gustav Sennton /** 27936bed13f8340359fac1c709460cfa95142c5e6a1Gustav Sennton * @return the directory of the native WebView library with bitness {@param is64bit}. 28036bed13f8340359fac1c709460cfa95142c5e6a1Gustav Sennton * @hide 28136bed13f8340359fac1c709460cfa95142c5e6a1Gustav Sennton */ 28236bed13f8340359fac1c709460cfa95142c5e6a1Gustav Sennton @VisibleForTesting 28336bed13f8340359fac1c709460cfa95142c5e6a1Gustav Sennton public static String getWebViewNativeLibraryDirectory(ApplicationInfo ai, boolean is64bit) { 28436bed13f8340359fac1c709460cfa95142c5e6a1Gustav Sennton // Primary arch has the same bitness as the library we are looking for. 28536bed13f8340359fac1c709460cfa95142c5e6a1Gustav Sennton if (is64bit == VMRuntime.is64BitAbi(ai.primaryCpuAbi)) return ai.nativeLibraryDir; 28636bed13f8340359fac1c709460cfa95142c5e6a1Gustav Sennton 28736bed13f8340359fac1c709460cfa95142c5e6a1Gustav Sennton // Secondary arch has the same bitness as the library we are looking for. 28836bed13f8340359fac1c709460cfa95142c5e6a1Gustav Sennton if (!TextUtils.isEmpty(ai.secondaryCpuAbi)) { 28936bed13f8340359fac1c709460cfa95142c5e6a1Gustav Sennton return ai.secondaryNativeLibraryDir; 290ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton } 29136bed13f8340359fac1c709460cfa95142c5e6a1Gustav Sennton 29236bed13f8340359fac1c709460cfa95142c5e6a1Gustav Sennton return ""; 29336bed13f8340359fac1c709460cfa95142c5e6a1Gustav Sennton } 29436bed13f8340359fac1c709460cfa95142c5e6a1Gustav Sennton 29536bed13f8340359fac1c709460cfa95142c5e6a1Gustav Sennton /** 29636bed13f8340359fac1c709460cfa95142c5e6a1Gustav Sennton * @return an object describing a native WebView library given the directory path of that 29736bed13f8340359fac1c709460cfa95142c5e6a1Gustav Sennton * library, or null if the library couldn't be found. 29836bed13f8340359fac1c709460cfa95142c5e6a1Gustav Sennton */ 29936bed13f8340359fac1c709460cfa95142c5e6a1Gustav Sennton @Nullable 30036bed13f8340359fac1c709460cfa95142c5e6a1Gustav Sennton private static WebViewNativeLibrary findNativeLibrary(ApplicationInfo ai, 30136bed13f8340359fac1c709460cfa95142c5e6a1Gustav Sennton String nativeLibFileName, String[] abiList, String libDirectory) 30236bed13f8340359fac1c709460cfa95142c5e6a1Gustav Sennton throws WebViewFactory.MissingWebViewPackageException { 30336bed13f8340359fac1c709460cfa95142c5e6a1Gustav Sennton if (TextUtils.isEmpty(libDirectory)) return null; 30436bed13f8340359fac1c709460cfa95142c5e6a1Gustav Sennton String libPath = libDirectory + "/" + nativeLibFileName; 30536bed13f8340359fac1c709460cfa95142c5e6a1Gustav Sennton File f = new File(libPath); 30636bed13f8340359fac1c709460cfa95142c5e6a1Gustav Sennton if (f.exists()) { 30736bed13f8340359fac1c709460cfa95142c5e6a1Gustav Sennton return new WebViewNativeLibrary(libPath, f.length()); 30836bed13f8340359fac1c709460cfa95142c5e6a1Gustav Sennton } else { 30936bed13f8340359fac1c709460cfa95142c5e6a1Gustav Sennton return getLoadFromApkPath(ai.sourceDir, abiList, nativeLibFileName); 310ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton } 31136bed13f8340359fac1c709460cfa95142c5e6a1Gustav Sennton } 312ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton 31336bed13f8340359fac1c709460cfa95142c5e6a1Gustav Sennton /** 31436bed13f8340359fac1c709460cfa95142c5e6a1Gustav Sennton * @hide 31536bed13f8340359fac1c709460cfa95142c5e6a1Gustav Sennton */ 31636bed13f8340359fac1c709460cfa95142c5e6a1Gustav Sennton @VisibleForTesting 31736bed13f8340359fac1c709460cfa95142c5e6a1Gustav Sennton public static class WebViewNativeLibrary { 31836bed13f8340359fac1c709460cfa95142c5e6a1Gustav Sennton public final String path; 31936bed13f8340359fac1c709460cfa95142c5e6a1Gustav Sennton public final long size; 32036bed13f8340359fac1c709460cfa95142c5e6a1Gustav Sennton 32136bed13f8340359fac1c709460cfa95142c5e6a1Gustav Sennton WebViewNativeLibrary(String path, long size) { 32236bed13f8340359fac1c709460cfa95142c5e6a1Gustav Sennton this.path = path; 32336bed13f8340359fac1c709460cfa95142c5e6a1Gustav Sennton this.size = size; 32436bed13f8340359fac1c709460cfa95142c5e6a1Gustav Sennton } 325ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton } 326ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton 32736bed13f8340359fac1c709460cfa95142c5e6a1Gustav Sennton private static WebViewNativeLibrary getLoadFromApkPath(String apkPath, 32836bed13f8340359fac1c709460cfa95142c5e6a1Gustav Sennton String[] abiList, 32936bed13f8340359fac1c709460cfa95142c5e6a1Gustav Sennton String nativeLibFileName) 330ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton throws WebViewFactory.MissingWebViewPackageException { 331ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton // Search the APK for a native library conforming to a listed ABI. 332ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton try (ZipFile z = new ZipFile(apkPath)) { 333ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton for (String abi : abiList) { 334ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton final String entry = "lib/" + abi + "/" + nativeLibFileName; 335ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton ZipEntry e = z.getEntry(entry); 336ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton if (e != null && e.getMethod() == ZipEntry.STORED) { 337ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton // Return a path formatted for dlopen() load from APK. 33836bed13f8340359fac1c709460cfa95142c5e6a1Gustav Sennton return new WebViewNativeLibrary(apkPath + "!/" + entry, e.getSize()); 339ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton } 340ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton } 341ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton } catch (IOException e) { 342ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton throw new WebViewFactory.MissingWebViewPackageException(e); 343ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton } 34436bed13f8340359fac1c709460cfa95142c5e6a1Gustav Sennton return null; 345ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton } 346ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton 347ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton /** 348ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton * Sets the size of the memory area in which to store the relro section. 349ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton */ 350ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton private static void setWebViewZygoteVmSize(long vmSize) { 351ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton SystemProperties.set(WebViewFactory.CHROMIUM_WEBVIEW_VMSIZE_SIZE_PROPERTY, 352ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton Long.toString(vmSize)); 353ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton } 354ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton 355ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton static native boolean nativeReserveAddressSpace(long addressSpaceToReserve); 356ae498f270230e20b5a777ed2d6387a21767625a3Gustav Sennton static native boolean nativeCreateRelroFile(String lib, String relro); 357ae498f270230e20b5a777ed2d6387a21767625a3Gustav Sennton static native int nativeLoadWithRelroFile(String lib, String relro, ClassLoader clazzLoader); 358ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton} 359