WebViewLibraryLoader.java revision 0e541ef99221d7681e2fe0d721e92c4d6c74073c
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 19ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Senntonimport android.app.ActivityManagerInternal; 20ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Senntonimport android.content.pm.ApplicationInfo; 21ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Senntonimport android.content.pm.PackageInfo; 22ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Senntonimport android.os.Build; 23ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Senntonimport android.os.Process; 24ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Senntonimport android.os.RemoteException; 25ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Senntonimport android.os.SystemProperties; 26ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Senntonimport android.text.TextUtils; 27ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Senntonimport android.util.Log; 28ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton 29ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Senntonimport com.android.server.LocalServices; 30ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton 31ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Senntonimport dalvik.system.VMRuntime; 32ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton 33ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Senntonimport java.io.File; 34ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Senntonimport java.io.IOException; 35ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Senntonimport java.util.Arrays; 36ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Senntonimport java.util.zip.ZipEntry; 37ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Senntonimport java.util.zip.ZipFile; 38ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton 39ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Senntonclass WebViewLibraryLoader { 40ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton private static final String LOGTAG = WebViewLibraryLoader.class.getSimpleName(); 41ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton 42ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton private static final String CHROMIUM_WEBVIEW_NATIVE_RELRO_32 = 43ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton "/data/misc/shared_relro/libwebviewchromium32.relro"; 44ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton private static final String CHROMIUM_WEBVIEW_NATIVE_RELRO_64 = 45ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton "/data/misc/shared_relro/libwebviewchromium64.relro"; 46ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton private static final long CHROMIUM_WEBVIEW_DEFAULT_VMSIZE_BYTES = 100 * 1024 * 1024; 47ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton 48ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton private static final boolean DEBUG = false; 49ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton 50ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton private static boolean sAddressSpaceReserved = false; 51ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton 52ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton /** 53ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton * Private class for running the actual relro creation in an unprivileged child process. 54ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton * RelroFileCreator is a static class (without access to the outer class) to avoid accidentally 55ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton * using any static members from the outer class. Those members will in reality differ between 56ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton * the child process in which RelroFileCreator operates, and the app process in which the static 57ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton * members of this class are used. 58ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton */ 59ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton private static class RelroFileCreator { 60ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton // Called in an unprivileged child process to create the relro file. 61ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton public static void main(String[] args) { 62ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton boolean result = false; 63ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton boolean is64Bit = VMRuntime.getRuntime().is64Bit(); 64ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton try { 65ae498f270230e20b5a777ed2d6387a21767625a3Gustav Sennton if (args.length != 1 || args[0] == null) { 66ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton Log.e(LOGTAG, "Invalid RelroFileCreator args: " + Arrays.toString(args)); 67ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton return; 68ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton } 69ae498f270230e20b5a777ed2d6387a21767625a3Gustav Sennton Log.v(LOGTAG, "RelroFileCreator (64bit = " + is64Bit + "), lib: " + args[0]); 70ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton if (!sAddressSpaceReserved) { 71ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton Log.e(LOGTAG, "can't create relro file; address space not reserved"); 72ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton return; 73ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton } 74ae498f270230e20b5a777ed2d6387a21767625a3Gustav Sennton result = nativeCreateRelroFile(args[0] /* path */, 75ae498f270230e20b5a777ed2d6387a21767625a3Gustav Sennton is64Bit ? CHROMIUM_WEBVIEW_NATIVE_RELRO_64 : 76ae498f270230e20b5a777ed2d6387a21767625a3Gustav Sennton CHROMIUM_WEBVIEW_NATIVE_RELRO_32); 77ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton if (result && DEBUG) Log.v(LOGTAG, "created relro file"); 78ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton } finally { 79ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton // We must do our best to always notify the update service, even if something fails. 80ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton try { 8129675b294126bd00bb51bc8616f476aa90abacf1Torne (Richard Coles) WebViewFactory.getUpdateServiceUnchecked().notifyRelroCreationCompleted(); 82ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton } catch (RemoteException e) { 83ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton Log.e(LOGTAG, "error notifying update service", e); 84ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton } 85ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton 86ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton if (!result) Log.e(LOGTAG, "failed to create relro file"); 87ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton 88ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton // Must explicitly exit or else this process will just sit around after we return. 89ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton System.exit(0); 90ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton } 91ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton } 92ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton } 93ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton 94ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton /** 95ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton * Create a single relro file by invoking an isolated process that to do the actual work. 96ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton */ 97ae498f270230e20b5a777ed2d6387a21767625a3Gustav Sennton static void createRelroFile(final boolean is64Bit, String nativeLibraryPath) { 98ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton final String abi = 99ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton is64Bit ? Build.SUPPORTED_64_BIT_ABIS[0] : Build.SUPPORTED_32_BIT_ABIS[0]; 100ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton 101ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton // crashHandler is invoked by the ActivityManagerService when the isolated process crashes. 102ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton Runnable crashHandler = new Runnable() { 103ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton @Override 104ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton public void run() { 105ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton try { 106ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton Log.e(LOGTAG, "relro file creator for " + abi + " crashed. Proceeding without"); 107ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton WebViewFactory.getUpdateService().notifyRelroCreationCompleted(); 108ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton } catch (RemoteException e) { 109ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton Log.e(LOGTAG, "Cannot reach WebViewUpdateService. " + e.getMessage()); 110ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton } 111ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton } 112ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton }; 113ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton 114ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton try { 115ae498f270230e20b5a777ed2d6387a21767625a3Gustav Sennton if (nativeLibraryPath == null) { 116ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton throw new IllegalArgumentException( 117ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton "Native library paths to the WebView RelRo process must not be null!"); 118ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton } 119ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton int pid = LocalServices.getService(ActivityManagerInternal.class).startIsolatedProcess( 120ae498f270230e20b5a777ed2d6387a21767625a3Gustav Sennton RelroFileCreator.class.getName(), new String[] { nativeLibraryPath }, 121ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton "WebViewLoader-" + abi, abi, Process.SHARED_RELRO_UID, crashHandler); 122ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton if (pid <= 0) throw new Exception("Failed to start the relro file creator process"); 123ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton } catch (Throwable t) { 124ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton // Log and discard errors as we must not crash the system server. 125ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton Log.e(LOGTAG, "error starting relro file creator for abi " + abi, t); 126ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton crashHandler.run(); 127ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton } 128ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton } 129ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton 1300e541ef99221d7681e2fe0d721e92c4d6c74073cGustav Sennton static int prepareNativeLibraries(PackageInfo webviewPackageInfo) 1310e541ef99221d7681e2fe0d721e92c4d6c74073cGustav Sennton throws WebViewFactory.MissingWebViewPackageException { 1320e541ef99221d7681e2fe0d721e92c4d6c74073cGustav Sennton String[] nativeLibs = updateWebViewZygoteVmSize(webviewPackageInfo); 1330e541ef99221d7681e2fe0d721e92c4d6c74073cGustav Sennton if (DEBUG) Log.v(LOGTAG, "creating relro files"); 1340e541ef99221d7681e2fe0d721e92c4d6c74073cGustav Sennton int numRelros = 0; 1350e541ef99221d7681e2fe0d721e92c4d6c74073cGustav Sennton 1360e541ef99221d7681e2fe0d721e92c4d6c74073cGustav Sennton // We must always trigger createRelRo regardless of the value of nativeLibraryPaths. Any 1370e541ef99221d7681e2fe0d721e92c4d6c74073cGustav Sennton // unexpected values will be handled there to ensure that we trigger notifying any process 1380e541ef99221d7681e2fe0d721e92c4d6c74073cGustav Sennton // waiting on relro creation. 1390e541ef99221d7681e2fe0d721e92c4d6c74073cGustav Sennton if (Build.SUPPORTED_32_BIT_ABIS.length > 0) { 1400e541ef99221d7681e2fe0d721e92c4d6c74073cGustav Sennton if (DEBUG) Log.v(LOGTAG, "Create 32 bit relro"); 1410e541ef99221d7681e2fe0d721e92c4d6c74073cGustav Sennton createRelroFile(false /* is64Bit */, nativeLibs[0]); 1420e541ef99221d7681e2fe0d721e92c4d6c74073cGustav Sennton numRelros++; 1430e541ef99221d7681e2fe0d721e92c4d6c74073cGustav Sennton } 1440e541ef99221d7681e2fe0d721e92c4d6c74073cGustav Sennton 1450e541ef99221d7681e2fe0d721e92c4d6c74073cGustav Sennton if (Build.SUPPORTED_64_BIT_ABIS.length > 0) { 1460e541ef99221d7681e2fe0d721e92c4d6c74073cGustav Sennton if (DEBUG) Log.v(LOGTAG, "Create 64 bit relro"); 1470e541ef99221d7681e2fe0d721e92c4d6c74073cGustav Sennton createRelroFile(true /* is64Bit */, nativeLibs[1]); 1480e541ef99221d7681e2fe0d721e92c4d6c74073cGustav Sennton numRelros++; 1490e541ef99221d7681e2fe0d721e92c4d6c74073cGustav Sennton } 1500e541ef99221d7681e2fe0d721e92c4d6c74073cGustav Sennton return numRelros; 1510e541ef99221d7681e2fe0d721e92c4d6c74073cGustav Sennton } 1520e541ef99221d7681e2fe0d721e92c4d6c74073cGustav Sennton 153ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton /** 154ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton * 155ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton * @return the native WebView libraries in the new WebView APK. 156ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton */ 1570e541ef99221d7681e2fe0d721e92c4d6c74073cGustav Sennton private static String[] updateWebViewZygoteVmSize(PackageInfo packageInfo) 158ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton throws WebViewFactory.MissingWebViewPackageException { 159ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton // Find the native libraries of the new WebView package, to change the size of the 160ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton // memory region in the Zygote reserved for the library. 161ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton String[] nativeLibs = getWebViewNativeLibraryPaths(packageInfo); 162ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton if (nativeLibs != null) { 163ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton long newVmSize = 0L; 164ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton 165ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton for (String path : nativeLibs) { 166ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton if (path == null || TextUtils.isEmpty(path)) continue; 167ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton if (DEBUG) Log.d(LOGTAG, "Checking file size of " + path); 168ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton File f = new File(path); 169ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton if (f.exists()) { 170ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton newVmSize = Math.max(newVmSize, f.length()); 171ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton continue; 172ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton } 173ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton if (path.contains("!/")) { 174ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton String[] split = TextUtils.split(path, "!/"); 175ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton if (split.length == 2) { 176ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton try (ZipFile z = new ZipFile(split[0])) { 177ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton ZipEntry e = z.getEntry(split[1]); 178ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton if (e != null && e.getMethod() == ZipEntry.STORED) { 179ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton newVmSize = Math.max(newVmSize, e.getSize()); 180ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton continue; 181ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton } 182ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton } 183ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton catch (IOException e) { 184ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton Log.e(LOGTAG, "error reading APK file " + split[0] + ", ", e); 185ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton } 186ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton } 187ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton } 188ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton Log.e(LOGTAG, "error sizing load for " + path); 189ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton } 190ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton 191ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton if (DEBUG) { 192ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton Log.v(LOGTAG, "Based on library size, need " + newVmSize 193ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton + " bytes of address space."); 194ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton } 195ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton // The required memory can be larger than the file on disk (due to .bss), and an 196ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton // upgraded version of the library will likely be larger, so always attempt to 197ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton // reserve twice as much as we think to allow for the library to grow during this 198ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton // boot cycle. 199ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton newVmSize = Math.max(2 * newVmSize, CHROMIUM_WEBVIEW_DEFAULT_VMSIZE_BYTES); 200ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton Log.d(LOGTAG, "Setting new address space to " + newVmSize); 201ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton setWebViewZygoteVmSize(newVmSize); 202ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton } 203ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton return nativeLibs; 204ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton } 205ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton 206ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton /** 207ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton * Reserve space for the native library to be loaded into. 208ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton */ 209ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton static void reserveAddressSpaceInZygote() { 210ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton System.loadLibrary("webviewchromium_loader"); 211ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton long addressSpaceToReserve = 212ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton SystemProperties.getLong(WebViewFactory.CHROMIUM_WEBVIEW_VMSIZE_SIZE_PROPERTY, 213ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton CHROMIUM_WEBVIEW_DEFAULT_VMSIZE_BYTES); 214ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton sAddressSpaceReserved = nativeReserveAddressSpace(addressSpaceToReserve); 215ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton 216ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton if (sAddressSpaceReserved) { 217ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton if (DEBUG) { 218ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton Log.v(LOGTAG, "address space reserved: " + addressSpaceToReserve + " bytes"); 219ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton } 220ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton } else { 221ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton Log.e(LOGTAG, "reserving " + addressSpaceToReserve + " bytes of address space failed"); 222ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton } 223ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton } 224ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton 225ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton /** 226ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton * Load WebView's native library into the current process. 227ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton * Note: assumes that we have waited for relro creation. 228ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton * @param clazzLoader class loader used to find the linker namespace to load the library into. 229ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton * @param packageInfo the package from which WebView is loaded. 230ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton */ 231ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton static int loadNativeLibrary(ClassLoader clazzLoader, PackageInfo packageInfo) 232ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton throws WebViewFactory.MissingWebViewPackageException { 233ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton if (!sAddressSpaceReserved) { 234ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton Log.e(LOGTAG, "can't load with relro file; address space not reserved"); 235ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton return WebViewFactory.LIBLOAD_ADDRESS_SPACE_NOT_RESERVED; 236ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton } 237ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton 238beec08679b7e0cfc10f1ef57072716b17ce417c3Gustav Sennton final String libraryFileName = 239beec08679b7e0cfc10f1ef57072716b17ce417c3Gustav Sennton WebViewFactory.getWebViewLibrary(packageInfo.applicationInfo); 240ae498f270230e20b5a777ed2d6387a21767625a3Gustav Sennton String relroPath = VMRuntime.getRuntime().is64Bit() ? CHROMIUM_WEBVIEW_NATIVE_RELRO_64 : 241ae498f270230e20b5a777ed2d6387a21767625a3Gustav Sennton CHROMIUM_WEBVIEW_NATIVE_RELRO_32; 242ae498f270230e20b5a777ed2d6387a21767625a3Gustav Sennton int result = nativeLoadWithRelroFile(libraryFileName, relroPath, clazzLoader); 243ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton if (result != WebViewFactory.LIBLOAD_SUCCESS) { 244ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton Log.w(LOGTAG, "failed to load with relro file, proceeding without"); 245ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton } else if (DEBUG) { 246ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton Log.v(LOGTAG, "loaded with relro file"); 247ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton } 248ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton return result; 249ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton } 250ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton 251ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton /** 252ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton * Fetch WebView's native library paths from {@param packageInfo}. 253ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton */ 254ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton static String[] getWebViewNativeLibraryPaths(PackageInfo packageInfo) 255ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton throws WebViewFactory.MissingWebViewPackageException { 256ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton ApplicationInfo ai = packageInfo.applicationInfo; 257ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton final String nativeLibFileName = WebViewFactory.getWebViewLibrary(ai); 258ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton 259ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton String path32; 260ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton String path64; 261ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton boolean primaryArchIs64bit = VMRuntime.is64BitAbi(ai.primaryCpuAbi); 262ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton if (!TextUtils.isEmpty(ai.secondaryCpuAbi)) { 263ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton // Multi-arch case. 264ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton if (primaryArchIs64bit) { 265ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton // Primary arch: 64-bit, secondary: 32-bit. 266ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton path64 = ai.nativeLibraryDir; 267ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton path32 = ai.secondaryNativeLibraryDir; 268ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton } else { 269ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton // Primary arch: 32-bit, secondary: 64-bit. 270ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton path64 = ai.secondaryNativeLibraryDir; 271ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton path32 = ai.nativeLibraryDir; 272ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton } 273ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton } else if (primaryArchIs64bit) { 274ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton // Single-arch 64-bit. 275ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton path64 = ai.nativeLibraryDir; 276ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton path32 = ""; 277ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton } else { 278ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton // Single-arch 32-bit. 279ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton path32 = ai.nativeLibraryDir; 280ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton path64 = ""; 281ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton } 282ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton 283ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton // Form the full paths to the extracted native libraries. 284ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton // If libraries were not extracted, try load from APK paths instead. 285ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton if (!TextUtils.isEmpty(path32)) { 286ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton path32 += "/" + nativeLibFileName; 287ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton File f = new File(path32); 288ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton if (!f.exists()) { 289ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton path32 = getLoadFromApkPath(ai.sourceDir, 290ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton Build.SUPPORTED_32_BIT_ABIS, 291ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton nativeLibFileName); 292ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton } 293ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton } 294ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton if (!TextUtils.isEmpty(path64)) { 295ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton path64 += "/" + nativeLibFileName; 296ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton File f = new File(path64); 297ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton if (!f.exists()) { 298ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton path64 = getLoadFromApkPath(ai.sourceDir, 299ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton Build.SUPPORTED_64_BIT_ABIS, 300ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton nativeLibFileName); 301ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton } 302ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton } 303ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton 304ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton if (DEBUG) Log.v(LOGTAG, "Native 32-bit lib: " + path32 + ", 64-bit lib: " + path64); 305ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton return new String[] { path32, path64 }; 306ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton } 307ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton 308ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton private static String getLoadFromApkPath(String apkPath, 309ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton String[] abiList, 310ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton String nativeLibFileName) 311ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton throws WebViewFactory.MissingWebViewPackageException { 312ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton // Search the APK for a native library conforming to a listed ABI. 313ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton try (ZipFile z = new ZipFile(apkPath)) { 314ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton for (String abi : abiList) { 315ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton final String entry = "lib/" + abi + "/" + nativeLibFileName; 316ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton ZipEntry e = z.getEntry(entry); 317ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton if (e != null && e.getMethod() == ZipEntry.STORED) { 318ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton // Return a path formatted for dlopen() load from APK. 319ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton return apkPath + "!/" + entry; 320ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton } 321ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton } 322ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton } catch (IOException e) { 323ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton throw new WebViewFactory.MissingWebViewPackageException(e); 324ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton } 325ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton return ""; 326ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton } 327ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton 328ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton /** 329ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton * Sets the size of the memory area in which to store the relro section. 330ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton */ 331ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton private static void setWebViewZygoteVmSize(long vmSize) { 332ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton SystemProperties.set(WebViewFactory.CHROMIUM_WEBVIEW_VMSIZE_SIZE_PROPERTY, 333ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton Long.toString(vmSize)); 334ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton } 335ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton 336ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton static native boolean nativeReserveAddressSpace(long addressSpaceToReserve); 337ae498f270230e20b5a777ed2d6387a21767625a3Gustav Sennton static native boolean nativeCreateRelroFile(String lib, String relro); 338ae498f270230e20b5a777ed2d6387a21767625a3Gustav Sennton static native int nativeLoadWithRelroFile(String lib, String relro, ClassLoader clazzLoader); 339ed98a156366846a56b8a143c86ab3b32f4da5ac3Gustav Sennton} 340