WebViewFactory.java revision e76e81a227a29db5223d231ec88ecb02fa4d6835
1d3101b1d300f5942fdb7dfa323dc8830c4edc007Jonathan Dixon/*
2d3101b1d300f5942fdb7dfa323dc8830c4edc007Jonathan Dixon * Copyright (C) 2012 The Android Open Source Project
3d3101b1d300f5942fdb7dfa323dc8830c4edc007Jonathan Dixon *
4d3101b1d300f5942fdb7dfa323dc8830c4edc007Jonathan Dixon * Licensed under the Apache License, Version 2.0 (the "License");
5d3101b1d300f5942fdb7dfa323dc8830c4edc007Jonathan Dixon * you may not use this file except in compliance with the License.
6d3101b1d300f5942fdb7dfa323dc8830c4edc007Jonathan Dixon * You may obtain a copy of the License at
7d3101b1d300f5942fdb7dfa323dc8830c4edc007Jonathan Dixon *
8d3101b1d300f5942fdb7dfa323dc8830c4edc007Jonathan Dixon *      http://www.apache.org/licenses/LICENSE-2.0
9d3101b1d300f5942fdb7dfa323dc8830c4edc007Jonathan Dixon *
10d3101b1d300f5942fdb7dfa323dc8830c4edc007Jonathan Dixon * Unless required by applicable law or agreed to in writing, software
11d3101b1d300f5942fdb7dfa323dc8830c4edc007Jonathan Dixon * distributed under the License is distributed on an "AS IS" BASIS,
12d3101b1d300f5942fdb7dfa323dc8830c4edc007Jonathan Dixon * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13d3101b1d300f5942fdb7dfa323dc8830c4edc007Jonathan Dixon * See the License for the specific language governing permissions and
14d3101b1d300f5942fdb7dfa323dc8830c4edc007Jonathan Dixon * limitations under the License.
15d3101b1d300f5942fdb7dfa323dc8830c4edc007Jonathan Dixon */
16d3101b1d300f5942fdb7dfa323dc8830c4edc007Jonathan Dixon
17d3101b1d300f5942fdb7dfa323dc8830c4edc007Jonathan Dixonpackage android.webkit;
18d3101b1d300f5942fdb7dfa323dc8830c4edc007Jonathan Dixon
19810c052d9b117217152c2a609ccec056a2a61d1ePrimiano Tucciimport android.app.ActivityManagerInternal;
2063d3d8a458cfc124ebd183994d3d152d3b06c1d8Marcin Kosibaimport android.app.Application;
216c778cebc73e7eb76510f6e2183d804b8c07082bTorne (Richard Coles)import android.app.AppGlobals;
226c778cebc73e7eb76510f6e2183d804b8c07082bTorne (Richard Coles)import android.content.Context;
231b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucciimport android.content.pm.ApplicationInfo;
246c778cebc73e7eb76510f6e2183d804b8c07082bTorne (Richard Coles)import android.content.pm.PackageManager;
2508cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)import android.os.Build;
2608cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)import android.os.Process;
2708cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)import android.os.RemoteException;
2808cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)import android.os.ServiceManager;
29e09e976dad1d974ca28381451b0bbbeafbb872d5Ben Murdochimport android.os.StrictMode;
305ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdochimport android.os.SystemProperties;
311b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucciimport android.text.TextUtils;
3203ce9b3e69f1eec85e7e7cbfd65bb9093e74cea8Torne (Richard Coles)import android.util.AndroidRuntimeException;
33d3101b1d300f5942fdb7dfa323dc8830c4edc007Jonathan Dixonimport android.util.Log;
34810c052d9b117217152c2a609ccec056a2a61d1ePrimiano Tucciimport com.android.server.LocalServices;
3508cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)import dalvik.system.VMRuntime;
3608cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)
3708cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)import java.io.File;
381b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucciimport java.util.Arrays;
3908cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)
4008cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)import com.android.internal.os.Zygote;
41d3101b1d300f5942fdb7dfa323dc8830c4edc007Jonathan Dixon
42d3101b1d300f5942fdb7dfa323dc8830c4edc007Jonathan Dixon/**
43d3101b1d300f5942fdb7dfa323dc8830c4edc007Jonathan Dixon * Top level factory, used creating all the main WebView implementation classes.
44b0e35846b818bdf0db9cafe881a8a535116d596eJared Duke *
45b0e35846b818bdf0db9cafe881a8a535116d596eJared Duke * @hide
46d3101b1d300f5942fdb7dfa323dc8830c4edc007Jonathan Dixon */
47b0e35846b818bdf0db9cafe881a8a535116d596eJared Dukepublic final class WebViewFactory {
48a7eaa8ee222611c28f050158db4b68c4d893a8a9Jonathan Dixon
49e09e976dad1d974ca28381451b0bbbeafbb872d5Ben Murdoch    private static final String CHROMIUM_WEBVIEW_FACTORY =
50a9bbd9439c3043bd76a7474e6dca3c8131b1b258Torne (Richard Coles)            "com.android.webview.chromium.WebViewChromiumFactoryProvider";
51d3101b1d300f5942fdb7dfa323dc8830c4edc007Jonathan Dixon
520e04bcfbdc1845c931b45b3498aef438b944e961Ben Murdoch    private static final String NULL_WEBVIEW_FACTORY =
530e04bcfbdc1845c931b45b3498aef438b944e961Ben Murdoch            "com.android.webview.nullwebview.NullWebViewFactoryProvider";
540e04bcfbdc1845c931b45b3498aef438b944e961Ben Murdoch
5508cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)    private static final String CHROMIUM_WEBVIEW_NATIVE_RELRO_32 =
5608cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)            "/data/misc/shared_relro/libwebviewchromium32.relro";
5708cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)    private static final String CHROMIUM_WEBVIEW_NATIVE_RELRO_64 =
5808cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)            "/data/misc/shared_relro/libwebviewchromium64.relro";
5908cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)
605ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdoch    public static final String CHROMIUM_WEBVIEW_VMSIZE_SIZE_PROPERTY =
615ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdoch            "persist.sys.webview.vmsize";
625ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdoch    private static final long CHROMIUM_WEBVIEW_DEFAULT_VMSIZE_BYTES = 100 * 1024 * 1024;
631b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucci
64d3101b1d300f5942fdb7dfa323dc8830c4edc007Jonathan Dixon    private static final String LOGTAG = "WebViewFactory";
65d3101b1d300f5942fdb7dfa323dc8830c4edc007Jonathan Dixon
66d3101b1d300f5942fdb7dfa323dc8830c4edc007Jonathan Dixon    private static final boolean DEBUG = false;
67d3101b1d300f5942fdb7dfa323dc8830c4edc007Jonathan Dixon
68d3101b1d300f5942fdb7dfa323dc8830c4edc007Jonathan Dixon    // Cache the factory both for efficiency, and ensure any one process gets all webviews from the
69d3101b1d300f5942fdb7dfa323dc8830c4edc007Jonathan Dixon    // same provider.
70d3101b1d300f5942fdb7dfa323dc8830c4edc007Jonathan Dixon    private static WebViewFactoryProvider sProviderInstance;
719f9d34552f53c534141584a5ad4a8a49ad7939dcJohn Reck    private static final Object sProviderLock = new Object();
7208cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)    private static boolean sAddressSpaceReserved = false;
73d3101b1d300f5942fdb7dfa323dc8830c4edc007Jonathan Dixon
74dc00a84af15ff3594a6dfa512be21095bf9fee82Ben Murdoch    public static String getWebViewPackageName() {
755651fc2feeed3af1bd0991e32788a8936d698811Torne (Richard Coles)        return AppGlobals.getInitialApplication().getString(
765651fc2feeed3af1bd0991e32788a8936d698811Torne (Richard Coles)                com.android.internal.R.string.config_webViewPackageName);
77dc00a84af15ff3594a6dfa512be21095bf9fee82Ben Murdoch    }
78dc00a84af15ff3594a6dfa512be21095bf9fee82Ben Murdoch
799f9d34552f53c534141584a5ad4a8a49ad7939dcJohn Reck    static WebViewFactoryProvider getProvider() {
809f9d34552f53c534141584a5ad4a8a49ad7939dcJohn Reck        synchronized (sProviderLock) {
819f9d34552f53c534141584a5ad4a8a49ad7939dcJohn Reck            // For now the main purpose of this function (and the factory abstraction) is to keep
82d892afc88d3c67a7fe1c9550bfa7a452051d031dTorne (Richard Coles)            // us honest and minimize usage of WebView internals when binding the proxy.
839f9d34552f53c534141584a5ad4a8a49ad7939dcJohn Reck            if (sProviderInstance != null) return sProviderInstance;
84d3101b1d300f5942fdb7dfa323dc8830c4edc007Jonathan Dixon
8508cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)            loadNativeLibrary();
8608cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)
8703ce9b3e69f1eec85e7e7cbfd65bb9093e74cea8Torne (Richard Coles)            Class<WebViewFactoryProvider> providerClass;
8803ce9b3e69f1eec85e7e7cbfd65bb9093e74cea8Torne (Richard Coles)            try {
8903ce9b3e69f1eec85e7e7cbfd65bb9093e74cea8Torne (Richard Coles)                providerClass = getFactoryClass();
9003ce9b3e69f1eec85e7e7cbfd65bb9093e74cea8Torne (Richard Coles)            } catch (ClassNotFoundException e) {
9103ce9b3e69f1eec85e7e7cbfd65bb9093e74cea8Torne (Richard Coles)                Log.e(LOGTAG, "error loading provider", e);
9203ce9b3e69f1eec85e7e7cbfd65bb9093e74cea8Torne (Richard Coles)                throw new AndroidRuntimeException(e);
93e09e976dad1d974ca28381451b0bbbeafbb872d5Ben Murdoch            }
94e09e976dad1d974ca28381451b0bbbeafbb872d5Ben Murdoch
9503ce9b3e69f1eec85e7e7cbfd65bb9093e74cea8Torne (Richard Coles)            StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
9603ce9b3e69f1eec85e7e7cbfd65bb9093e74cea8Torne (Richard Coles)            try {
9703ce9b3e69f1eec85e7e7cbfd65bb9093e74cea8Torne (Richard Coles)                sProviderInstance = providerClass.newInstance();
9803ce9b3e69f1eec85e7e7cbfd65bb9093e74cea8Torne (Richard Coles)                if (DEBUG) Log.v(LOGTAG, "Loaded provider: " + sProviderInstance);
9903ce9b3e69f1eec85e7e7cbfd65bb9093e74cea8Torne (Richard Coles)                return sProviderInstance;
10003ce9b3e69f1eec85e7e7cbfd65bb9093e74cea8Torne (Richard Coles)            } catch (Exception e) {
10103ce9b3e69f1eec85e7e7cbfd65bb9093e74cea8Torne (Richard Coles)                Log.e(LOGTAG, "error instantiating provider", e);
10203ce9b3e69f1eec85e7e7cbfd65bb9093e74cea8Torne (Richard Coles)                throw new AndroidRuntimeException(e);
10303ce9b3e69f1eec85e7e7cbfd65bb9093e74cea8Torne (Richard Coles)            } finally {
10403ce9b3e69f1eec85e7e7cbfd65bb9093e74cea8Torne (Richard Coles)                StrictMode.setThreadPolicy(oldPolicy);
105e09e976dad1d974ca28381451b0bbbeafbb872d5Ben Murdoch            }
106d3101b1d300f5942fdb7dfa323dc8830c4edc007Jonathan Dixon        }
107d3101b1d300f5942fdb7dfa323dc8830c4edc007Jonathan Dixon    }
108d3101b1d300f5942fdb7dfa323dc8830c4edc007Jonathan Dixon
10903ce9b3e69f1eec85e7e7cbfd65bb9093e74cea8Torne (Richard Coles)    private static Class<WebViewFactoryProvider> getFactoryClass() throws ClassNotFoundException {
11063d3d8a458cfc124ebd183994d3d152d3b06c1d8Marcin Kosiba        Application initialApplication = AppGlobals.getInitialApplication();
1110e04bcfbdc1845c931b45b3498aef438b944e961Ben Murdoch        try {
11263d3d8a458cfc124ebd183994d3d152d3b06c1d8Marcin Kosiba            Context webViewContext = initialApplication.createPackageContext(
1136c778cebc73e7eb76510f6e2183d804b8c07082bTorne (Richard Coles)                    getWebViewPackageName(),
1146c778cebc73e7eb76510f6e2183d804b8c07082bTorne (Richard Coles)                    Context.CONTEXT_INCLUDE_CODE | Context.CONTEXT_IGNORE_SECURITY);
11563d3d8a458cfc124ebd183994d3d152d3b06c1d8Marcin Kosiba            initialApplication.getAssets().addAssetPath(
11663d3d8a458cfc124ebd183994d3d152d3b06c1d8Marcin Kosiba                    webViewContext.getApplicationInfo().sourceDir);
1176c778cebc73e7eb76510f6e2183d804b8c07082bTorne (Richard Coles)            ClassLoader clazzLoader = webViewContext.getClassLoader();
1186c778cebc73e7eb76510f6e2183d804b8c07082bTorne (Richard Coles)            return (Class<WebViewFactoryProvider>) Class.forName(CHROMIUM_WEBVIEW_FACTORY, true,
1196c778cebc73e7eb76510f6e2183d804b8c07082bTorne (Richard Coles)                                                                 clazzLoader);
1206c778cebc73e7eb76510f6e2183d804b8c07082bTorne (Richard Coles)        } catch (PackageManager.NameNotFoundException e) {
1216c778cebc73e7eb76510f6e2183d804b8c07082bTorne (Richard Coles)            Log.e(LOGTAG, "Chromium WebView package does not exist");
1220e04bcfbdc1845c931b45b3498aef438b944e961Ben Murdoch            return (Class<WebViewFactoryProvider>) Class.forName(NULL_WEBVIEW_FACTORY);
1230e04bcfbdc1845c931b45b3498aef438b944e961Ben Murdoch        }
124d3101b1d300f5942fdb7dfa323dc8830c4edc007Jonathan Dixon    }
12508cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)
12608cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)    /**
12708cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)     * Perform any WebView loading preparations that must happen in the zygote.
12808cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)     * Currently, this means allocating address space to load the real JNI library later.
12908cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)     */
13008cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)    public static void prepareWebViewInZygote() {
13108cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)        try {
13208cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)            System.loadLibrary("webviewchromium_loader");
1335ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdoch            long addressSpaceToReserve =
1345ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdoch                    SystemProperties.getLong(CHROMIUM_WEBVIEW_VMSIZE_SIZE_PROPERTY,
1355ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdoch                    CHROMIUM_WEBVIEW_DEFAULT_VMSIZE_BYTES);
1365ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdoch            sAddressSpaceReserved = nativeReserveAddressSpace(addressSpaceToReserve);
1375ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdoch
13808cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)            if (sAddressSpaceReserved) {
1395ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdoch                if (DEBUG) {
1405ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdoch                    Log.v(LOGTAG, "address space reserved: " + addressSpaceToReserve + " bytes");
1415ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdoch                }
14208cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)            } else {
1435ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdoch                Log.e(LOGTAG, "reserving " + addressSpaceToReserve +
1445ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdoch                        " bytes of address space failed");
14508cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)            }
146810c052d9b117217152c2a609ccec056a2a61d1ePrimiano Tucci        } catch (Throwable t) {
14708cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)            // Log and discard errors at this stage as we must not crash the zygote.
148810c052d9b117217152c2a609ccec056a2a61d1ePrimiano Tucci            Log.e(LOGTAG, "error preparing native loader", t);
14908cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)        }
15008cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)    }
15108cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)
15208cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)    /**
15308cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)     * Perform any WebView loading preparations that must happen at boot from the system server,
1545ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdoch     * after the package manager has started or after an update to the webview is installed.
15508cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)     * This must be called in the system server.
15608cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)     * Currently, this means spawning the child processes which will create the relro files.
15708cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)     */
15808cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)    public static void prepareWebViewInSystemServer() {
1595ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdoch        String[] nativePaths = null;
1605ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdoch        try {
1615ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdoch            nativePaths = getWebViewNativeLibraryPaths();
1625ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdoch        } catch (PackageManager.NameNotFoundException e) {
1635ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdoch        }
1645ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdoch        prepareWebViewInSystemServer(nativePaths);
1655ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdoch    }
1665ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdoch
1675ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdoch    private static void prepareWebViewInSystemServer(String[] nativeLibraryPaths) {
16808cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)        if (DEBUG) Log.v(LOGTAG, "creating relro files");
1695ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdoch
1705ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdoch        // We must always trigger createRelRo regardless of the value of nativeLibraryPaths. Any
1715ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdoch        // unexpected values will be handled there to ensure that we trigger notifying any process
1725ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdoch        // waiting on relreo creation.
1735ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdoch        if (Build.SUPPORTED_32_BIT_ABIS.length > 0) {
1745ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdoch            if (DEBUG) Log.v(LOGTAG, "Create 32 bit relro");
1755ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdoch            createRelroFile(false /* is64Bit */, nativeLibraryPaths);
1765ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdoch        }
1775ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdoch
1785ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdoch        if (Build.SUPPORTED_64_BIT_ABIS.length > 0) {
1795ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdoch            if (DEBUG) Log.v(LOGTAG, "Create 64 bit relro");
1805ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdoch            createRelroFile(true /* is64Bit */, nativeLibraryPaths);
1815ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdoch        }
1825ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdoch    }
1835ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdoch
1845ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdoch    public static void onWebViewUpdateInstalled() {
1855ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdoch        String[] nativeLibs = null;
1865ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdoch        try {
1875ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdoch            nativeLibs = WebViewFactory.getWebViewNativeLibraryPaths();
1885ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdoch        } catch (PackageManager.NameNotFoundException e) {
18908cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)        }
1905ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdoch
1915ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdoch        if (nativeLibs != null) {
1925ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdoch            long newVmSize = 0L;
1935ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdoch
1945ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdoch            for (String path : nativeLibs) {
1955ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdoch                if (DEBUG) Log.d(LOGTAG, "Checking file size of " + path);
1965ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdoch                if (path == null) continue;
1975ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdoch                File f = new File(path);
1985ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdoch                if (f.exists()) {
1995ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdoch                    long length = f.length();
2005ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdoch                    if (length > newVmSize) {
2015ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdoch                        newVmSize = length;
2025ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdoch                    }
2035ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdoch                }
2045ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdoch            }
2055ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdoch
2065ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdoch            if (DEBUG) {
2075ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdoch                Log.v(LOGTAG, "Based on library size, need " + newVmSize +
2085ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdoch                        " bytes of address space.");
2095ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdoch            }
2105ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdoch            // The required memory can be larger than the file on disk (due to .bss), and an
2115ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdoch            // upgraded version of the library will likely be larger, so always attempt to reserve
2125ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdoch            // twice as much as we think to allow for the library to grow during this boot cycle.
2135ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdoch            newVmSize = Math.max(2 * newVmSize, CHROMIUM_WEBVIEW_DEFAULT_VMSIZE_BYTES);
2145ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdoch            Log.d(LOGTAG, "Setting new address space to " + newVmSize);
2155ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdoch            SystemProperties.set(CHROMIUM_WEBVIEW_VMSIZE_SIZE_PROPERTY,
2165ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdoch                    Long.toString(newVmSize));
21708cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)        }
2185ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdoch        prepareWebViewInSystemServer(nativeLibs);
21908cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)    }
22008cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)
2211b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucci    private static String[] getWebViewNativeLibraryPaths()
2221b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucci            throws PackageManager.NameNotFoundException {
2231b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucci        final String NATIVE_LIB_FILE_NAME = "libwebviewchromium.so";
2241b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucci
2251b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucci        PackageManager pm = AppGlobals.getInitialApplication().getPackageManager();
2261b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucci        ApplicationInfo ai = pm.getApplicationInfo(getWebViewPackageName(), 0);
2271b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucci
2281b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucci        String path32;
2291b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucci        String path64;
2301b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucci        boolean primaryArchIs64bit = VMRuntime.is64BitAbi(ai.primaryCpuAbi);
2311b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucci        if (!TextUtils.isEmpty(ai.secondaryCpuAbi)) {
2321b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucci            // Multi-arch case.
2331b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucci            if (primaryArchIs64bit) {
2341b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucci                // Primary arch: 64-bit, secondary: 32-bit.
2351b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucci                path64 = ai.nativeLibraryDir;
2361b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucci                path32 = ai.secondaryNativeLibraryDir;
2371b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucci            } else {
2381b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucci                // Primary arch: 32-bit, secondary: 64-bit.
2391b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucci                path64 = ai.secondaryNativeLibraryDir;
2401b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucci                path32 = ai.nativeLibraryDir;
2411b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucci            }
2421b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucci        } else if (primaryArchIs64bit) {
2431b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucci            // Single-arch 64-bit.
2441b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucci            path64 = ai.nativeLibraryDir;
2451b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucci            path32 = "";
2461b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucci        } else {
2471b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucci            // Single-arch 32-bit.
2481b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucci            path32 = ai.nativeLibraryDir;
2491b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucci            path64 = "";
2501b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucci        }
2511b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucci        if (!TextUtils.isEmpty(path32)) path32 += "/" + NATIVE_LIB_FILE_NAME;
2521b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucci        if (!TextUtils.isEmpty(path64)) path64 += "/" + NATIVE_LIB_FILE_NAME;
2531b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucci        return new String[] { path32, path64 };
2541b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucci    }
2551b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucci
2565ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdoch    private static void createRelroFile(final boolean is64Bit, String[] nativeLibraryPaths) {
2571b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucci        final String abi =
2581b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucci                is64Bit ? Build.SUPPORTED_64_BIT_ABIS[0] : Build.SUPPORTED_32_BIT_ABIS[0];
259810c052d9b117217152c2a609ccec056a2a61d1ePrimiano Tucci
260810c052d9b117217152c2a609ccec056a2a61d1ePrimiano Tucci        // crashHandler is invoked by the ActivityManagerService when the isolated process crashes.
261810c052d9b117217152c2a609ccec056a2a61d1ePrimiano Tucci        Runnable crashHandler = new Runnable() {
262810c052d9b117217152c2a609ccec056a2a61d1ePrimiano Tucci            @Override
263810c052d9b117217152c2a609ccec056a2a61d1ePrimiano Tucci            public void run() {
264810c052d9b117217152c2a609ccec056a2a61d1ePrimiano Tucci                try {
2651b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucci                    Log.e(LOGTAG, "relro file creator for " + abi + " crashed. Proceeding without");
266810c052d9b117217152c2a609ccec056a2a61d1ePrimiano Tucci                    getUpdateService().notifyRelroCreationCompleted(is64Bit, false);
267810c052d9b117217152c2a609ccec056a2a61d1ePrimiano Tucci                } catch (RemoteException e) {
268810c052d9b117217152c2a609ccec056a2a61d1ePrimiano Tucci                    Log.e(LOGTAG, "Cannot reach WebViewUpdateService. " + e.getMessage());
269810c052d9b117217152c2a609ccec056a2a61d1ePrimiano Tucci                }
270810c052d9b117217152c2a609ccec056a2a61d1ePrimiano Tucci            }
271810c052d9b117217152c2a609ccec056a2a61d1ePrimiano Tucci        };
272810c052d9b117217152c2a609ccec056a2a61d1ePrimiano Tucci
27308cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)        try {
2745ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdoch            if (nativeLibraryPaths == null
2755ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdoch                    || nativeLibraryPaths[0] == null || nativeLibraryPaths[1] == null) {
2765ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdoch                throw new IllegalArgumentException(
2775ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdoch                        "Native library paths to the WebView RelRo process must not be null!");
2785ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdoch            }
279161536b5970ba5ab43233e7695ef69ba2bb804f4Primiano Tucci            int pid = LocalServices.getService(ActivityManagerInternal.class).startIsolatedProcess(
2805ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdoch                    RelroFileCreator.class.getName(), nativeLibraryPaths, "WebViewLoader-" + abi, abi,
281810c052d9b117217152c2a609ccec056a2a61d1ePrimiano Tucci                    Process.SHARED_RELRO_UID, crashHandler);
282e76e81a227a29db5223d231ec88ecb02fa4d6835Primiano Tucci            if (pid <= 0) throw new Exception("Failed to start the relro file creator process");
283810c052d9b117217152c2a609ccec056a2a61d1ePrimiano Tucci        } catch (Throwable t) {
28408cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)            // Log and discard errors as we must not crash the system server.
285810c052d9b117217152c2a609ccec056a2a61d1ePrimiano Tucci            Log.e(LOGTAG, "error starting relro file creator for abi " + abi, t);
286810c052d9b117217152c2a609ccec056a2a61d1ePrimiano Tucci            crashHandler.run();
28708cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)        }
28808cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)    }
28908cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)
29008cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)    private static class RelroFileCreator {
29108cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)        // Called in an unprivileged child process to create the relro file.
29208cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)        public static void main(String[] args) {
293161536b5970ba5ab43233e7695ef69ba2bb804f4Primiano Tucci            boolean result = false;
294161536b5970ba5ab43233e7695ef69ba2bb804f4Primiano Tucci            boolean is64Bit = VMRuntime.getRuntime().is64Bit();
2951b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucci            try{
2961b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucci                if (args.length != 2 || args[0] == null || args[1] == null) {
2971b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucci                    Log.e(LOGTAG, "Invalid RelroFileCreator args: " + Arrays.toString(args));
2981b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucci                    return;
2991b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucci                }
3001b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucci                Log.v(LOGTAG, "RelroFileCreator (64bit = " + is64Bit + "), " +
3011b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucci                        " 32-bit lib: " + args[0] + ", 64-bit lib: " + args[1]);
3021b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucci                if (!sAddressSpaceReserved) {
3031b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucci                    Log.e(LOGTAG, "can't create relro file; address space not reserved");
3041b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucci                    return;
3051b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucci                }
306161536b5970ba5ab43233e7695ef69ba2bb804f4Primiano Tucci                result = nativeCreateRelroFile(args[0] /* path32 */,
307161536b5970ba5ab43233e7695ef69ba2bb804f4Primiano Tucci                                               args[1] /* path64 */,
308161536b5970ba5ab43233e7695ef69ba2bb804f4Primiano Tucci                                               CHROMIUM_WEBVIEW_NATIVE_RELRO_32,
309161536b5970ba5ab43233e7695ef69ba2bb804f4Primiano Tucci                                               CHROMIUM_WEBVIEW_NATIVE_RELRO_64);
310e76e81a227a29db5223d231ec88ecb02fa4d6835Primiano Tucci                if (result && DEBUG) Log.v(LOGTAG, "created relro file");
311161536b5970ba5ab43233e7695ef69ba2bb804f4Primiano Tucci            } finally {
312161536b5970ba5ab43233e7695ef69ba2bb804f4Primiano Tucci                // We must do our best to always notify the update service, even if something fails.
3131b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucci                try {
3141b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucci                    getUpdateService().notifyRelroCreationCompleted(is64Bit, result);
3151b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucci                } catch (RemoteException e) {
3161b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucci                    Log.e(LOGTAG, "error notifying update service", e);
3171b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucci                }
318161536b5970ba5ab43233e7695ef69ba2bb804f4Primiano Tucci
319161536b5970ba5ab43233e7695ef69ba2bb804f4Primiano Tucci                if (!result) Log.e(LOGTAG, "failed to create relro file");
320161536b5970ba5ab43233e7695ef69ba2bb804f4Primiano Tucci
3211b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucci                // Must explicitly exit or else this process will just sit around after we return.
3221b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucci                System.exit(0);
3231b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucci            }
32408cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)        }
32508cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)    }
32608cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)
32708cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)    private static void loadNativeLibrary() {
32808cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)        if (!sAddressSpaceReserved) {
32908cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)            Log.e(LOGTAG, "can't load with relro file; address space not reserved");
33008cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)            return;
33108cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)        }
33208cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)
33308cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)        try {
33408cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)            getUpdateService().waitForRelroCreationCompleted(VMRuntime.getRuntime().is64Bit());
33508cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)        } catch (RemoteException e) {
33608cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)            Log.e(LOGTAG, "error waiting for relro creation, proceeding without", e);
33708cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)            return;
33808cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)        }
33908cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)
3401b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucci        try {
3411b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucci            String[] args = getWebViewNativeLibraryPaths();
3421b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucci            boolean result = nativeLoadWithRelroFile(args[0] /* path32 */,
3431b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucci                                                     args[1] /* path64 */,
3441b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucci                                                     CHROMIUM_WEBVIEW_NATIVE_RELRO_32,
3451b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucci                                                     CHROMIUM_WEBVIEW_NATIVE_RELRO_64);
3461b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucci            if (!result) {
3471b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucci                Log.w(LOGTAG, "failed to load with relro file, proceeding without");
3481b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucci            } else if (DEBUG) {
3491b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucci                Log.v(LOGTAG, "loaded with relro file");
3501b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucci            }
3511b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucci        } catch (PackageManager.NameNotFoundException e) {
3521b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucci            Log.e(LOGTAG, "Failed to list WebView package libraries for loadNativeLibrary", e);
35308cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)        }
35408cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)    }
35508cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)
35608cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)    private static IWebViewUpdateService getUpdateService() {
35708cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)        return IWebViewUpdateService.Stub.asInterface(ServiceManager.getService("webviewupdate"));
35808cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)    }
35908cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)
3605ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdoch    private static native boolean nativeReserveAddressSpace(long addressSpaceToReserve);
36108cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)    private static native boolean nativeCreateRelroFile(String lib32, String lib64,
36208cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)                                                        String relro32, String relro64);
36308cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)    private static native boolean nativeLoadWithRelroFile(String lib32, String lib64,
36408cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)                                                          String relro32, String relro64);
365d3101b1d300f5942fdb7dfa323dc8830c4edc007Jonathan Dixon}
366