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