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
19451e338c51e8c45efc0d21536dfae6f78f6d5e06Ignacio Sollaimport android.annotation.SystemApi;
20810c052d9b117217152c2a609ccec056a2a61d1ePrimiano Tucciimport android.app.ActivityManagerInternal;
216c778cebc73e7eb76510f6e2183d804b8c07082bTorne (Richard Coles)import android.app.AppGlobals;
2285844916b8a7cc7f6aabc6c37af7380a4c000bcbJeff Sharkeyimport android.app.Application;
236c778cebc73e7eb76510f6e2183d804b8c07082bTorne (Richard Coles)import android.content.Context;
241b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucciimport android.content.pm.ApplicationInfo;
250606cd572ad345fb2c40456509feac626c68dee3Torne (Richard Coles)import android.content.pm.PackageInfo;
266c778cebc73e7eb76510f6e2183d804b8c07082bTorne (Richard Coles)import android.content.pm.PackageManager;
2708cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)import android.os.Build;
2808cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)import android.os.Process;
2908cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)import android.os.RemoteException;
3008cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)import android.os.ServiceManager;
31e09e976dad1d974ca28381451b0bbbeafbb872d5Ben Murdochimport android.os.StrictMode;
325ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdochimport android.os.SystemProperties;
333822882b32d9b1b803aaff9b657a91d680f1d0f9Torne (Richard Coles)import android.os.Trace;
341b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucciimport android.text.TextUtils;
3503ce9b3e69f1eec85e7e7cbfd65bb9093e74cea8Torne (Richard Coles)import android.util.AndroidRuntimeException;
36d3101b1d300f5942fdb7dfa323dc8830c4edc007Jonathan Dixonimport android.util.Log;
3785844916b8a7cc7f6aabc6c37af7380a4c000bcbJeff Sharkey
38810c052d9b117217152c2a609ccec056a2a61d1ePrimiano Tucciimport com.android.server.LocalServices;
3985844916b8a7cc7f6aabc6c37af7380a4c000bcbJeff Sharkey
4008cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)import dalvik.system.VMRuntime;
4108cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)
4208cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)import java.io.File;
43b98082dcfb45a82d9b12dbf0d2f88acffe96a1c4Simon Baldwinimport java.io.IOException;
441b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucciimport java.util.Arrays;
45b98082dcfb45a82d9b12dbf0d2f88acffe96a1c4Simon Baldwinimport java.util.zip.ZipEntry;
46b98082dcfb45a82d9b12dbf0d2f88acffe96a1c4Simon Baldwinimport java.util.zip.ZipFile;
4708cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)
48d3101b1d300f5942fdb7dfa323dc8830c4edc007Jonathan Dixon/**
49d3101b1d300f5942fdb7dfa323dc8830c4edc007Jonathan Dixon * Top level factory, used creating all the main WebView implementation classes.
50b0e35846b818bdf0db9cafe881a8a535116d596eJared Duke *
51b0e35846b818bdf0db9cafe881a8a535116d596eJared Duke * @hide
52d3101b1d300f5942fdb7dfa323dc8830c4edc007Jonathan Dixon */
53451e338c51e8c45efc0d21536dfae6f78f6d5e06Ignacio Solla@SystemApi
54b0e35846b818bdf0db9cafe881a8a535116d596eJared Dukepublic final class WebViewFactory {
55a7eaa8ee222611c28f050158db4b68c4d893a8a9Jonathan Dixon
56e09e976dad1d974ca28381451b0bbbeafbb872d5Ben Murdoch    private static final String CHROMIUM_WEBVIEW_FACTORY =
57a9bbd9439c3043bd76a7474e6dca3c8131b1b258Torne (Richard Coles)            "com.android.webview.chromium.WebViewChromiumFactoryProvider";
58d3101b1d300f5942fdb7dfa323dc8830c4edc007Jonathan Dixon
590e04bcfbdc1845c931b45b3498aef438b944e961Ben Murdoch    private static final String NULL_WEBVIEW_FACTORY =
600e04bcfbdc1845c931b45b3498aef438b944e961Ben Murdoch            "com.android.webview.nullwebview.NullWebViewFactoryProvider";
610e04bcfbdc1845c931b45b3498aef438b944e961Ben Murdoch
6208cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)    private static final String CHROMIUM_WEBVIEW_NATIVE_RELRO_32 =
6308cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)            "/data/misc/shared_relro/libwebviewchromium32.relro";
6408cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)    private static final String CHROMIUM_WEBVIEW_NATIVE_RELRO_64 =
6508cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)            "/data/misc/shared_relro/libwebviewchromium64.relro";
6608cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)
675ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdoch    public static final String CHROMIUM_WEBVIEW_VMSIZE_SIZE_PROPERTY =
685ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdoch            "persist.sys.webview.vmsize";
695ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdoch    private static final long CHROMIUM_WEBVIEW_DEFAULT_VMSIZE_BYTES = 100 * 1024 * 1024;
701b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucci
71d3101b1d300f5942fdb7dfa323dc8830c4edc007Jonathan Dixon    private static final String LOGTAG = "WebViewFactory";
72d3101b1d300f5942fdb7dfa323dc8830c4edc007Jonathan Dixon
73d3101b1d300f5942fdb7dfa323dc8830c4edc007Jonathan Dixon    private static final boolean DEBUG = false;
74d3101b1d300f5942fdb7dfa323dc8830c4edc007Jonathan Dixon
75d3101b1d300f5942fdb7dfa323dc8830c4edc007Jonathan Dixon    // Cache the factory both for efficiency, and ensure any one process gets all webviews from the
76d3101b1d300f5942fdb7dfa323dc8830c4edc007Jonathan Dixon    // same provider.
77d3101b1d300f5942fdb7dfa323dc8830c4edc007Jonathan Dixon    private static WebViewFactoryProvider sProviderInstance;
789f9d34552f53c534141584a5ad4a8a49ad7939dcJohn Reck    private static final Object sProviderLock = new Object();
7908cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)    private static boolean sAddressSpaceReserved = false;
8084392d74fef177a87bc96a255761daf39569e726Torne (Richard Coles)    private static PackageInfo sPackageInfo;
81d3101b1d300f5942fdb7dfa323dc8830c4edc007Jonathan Dixon
8285edb6c6bff62e163e4490951ec49a958c63fad0Gustav Sennton    // Error codes for loadWebViewNativeLibraryFromPackage
8385edb6c6bff62e163e4490951ec49a958c63fad0Gustav Sennton    public static final int LIBLOAD_SUCCESS = 0;
8485edb6c6bff62e163e4490951ec49a958c63fad0Gustav Sennton    public static final int LIBLOAD_WRONG_PACKAGE_NAME = 1;
8585edb6c6bff62e163e4490951ec49a958c63fad0Gustav Sennton    public static final int LIBLOAD_ADDRESS_SPACE_NOT_RESERVED = 2;
8685edb6c6bff62e163e4490951ec49a958c63fad0Gustav Sennton    public static final int LIBLOAD_FAILED_WAITING_FOR_RELRO = 3;
8785edb6c6bff62e163e4490951ec49a958c63fad0Gustav Sennton    public static final int LIBLOAD_FAILED_LISTING_WEBVIEW_PACKAGES = 4;
8885edb6c6bff62e163e4490951ec49a958c63fad0Gustav Sennton
8985edb6c6bff62e163e4490951ec49a958c63fad0Gustav Sennton    // native relro loading error codes
9085edb6c6bff62e163e4490951ec49a958c63fad0Gustav Sennton    public static final int LIBLOAD_FAILED_TO_OPEN_RELRO_FILE = 5;
9185edb6c6bff62e163e4490951ec49a958c63fad0Gustav Sennton    public static final int LIBLOAD_FAILED_TO_LOAD_LIBRARY = 6;
9285edb6c6bff62e163e4490951ec49a958c63fad0Gustav Sennton    public static final int LIBLOAD_FAILED_JNI_CALL = 7;
9385edb6c6bff62e163e4490951ec49a958c63fad0Gustav Sennton
94a8366e78b58aeb392a9dcc7301183e881d99c783Gustav Sennton    private static class MissingWebViewPackageException extends AndroidRuntimeException {
95a8366e78b58aeb392a9dcc7301183e881d99c783Gustav Sennton        public MissingWebViewPackageException(String message) { super(message); }
96a8366e78b58aeb392a9dcc7301183e881d99c783Gustav Sennton        public MissingWebViewPackageException(Exception e) { super(e); }
97a8366e78b58aeb392a9dcc7301183e881d99c783Gustav Sennton    }
98a8366e78b58aeb392a9dcc7301183e881d99c783Gustav Sennton
99dc00a84af15ff3594a6dfa512be21095bf9fee82Ben Murdoch    public static String getWebViewPackageName() {
100d9730182212b157083321ea4e2209182f1fbb72fGustav Sennton        return AppGlobals.getInitialApplication().getString(
101d9730182212b157083321ea4e2209182f1fbb72fGustav Sennton                com.android.internal.R.string.config_webViewPackageName);
1022ed6fee15c85ff991f64ecfa8c1c4738e0fdf9b6Gustav Sennton    }
1032ed6fee15c85ff991f64ecfa8c1c4738e0fdf9b6Gustav Sennton
104d9730182212b157083321ea4e2209182f1fbb72fGustav Sennton    private static PackageInfo fetchPackageInfo() {
1052ed6fee15c85ff991f64ecfa8c1c4738e0fdf9b6Gustav Sennton        PackageManager pm = AppGlobals.getInitialApplication().getPackageManager();
106d9730182212b157083321ea4e2209182f1fbb72fGustav Sennton        try {
107d9730182212b157083321ea4e2209182f1fbb72fGustav Sennton            return pm.getPackageInfo(getWebViewPackageName(), PackageManager.GET_META_DATA);
108d9730182212b157083321ea4e2209182f1fbb72fGustav Sennton        } catch (PackageManager.NameNotFoundException e) {
109d9730182212b157083321ea4e2209182f1fbb72fGustav Sennton            throw new MissingWebViewPackageException(e);
1102ed6fee15c85ff991f64ecfa8c1c4738e0fdf9b6Gustav Sennton        }
1112ed6fee15c85ff991f64ecfa8c1c4738e0fdf9b6Gustav Sennton    }
1122ed6fee15c85ff991f64ecfa8c1c4738e0fdf9b6Gustav Sennton
113a8366e78b58aeb392a9dcc7301183e881d99c783Gustav Sennton    // throws MissingWebViewPackageException
1142ed6fee15c85ff991f64ecfa8c1c4738e0fdf9b6Gustav Sennton    private static ApplicationInfo getWebViewApplicationInfo() {
115d9730182212b157083321ea4e2209182f1fbb72fGustav Sennton        if (sPackageInfo == null) {
116d9730182212b157083321ea4e2209182f1fbb72fGustav Sennton            return fetchPackageInfo().applicationInfo;
117d9730182212b157083321ea4e2209182f1fbb72fGustav Sennton        } else {
1182ed6fee15c85ff991f64ecfa8c1c4738e0fdf9b6Gustav Sennton            return sPackageInfo.applicationInfo;
119d9730182212b157083321ea4e2209182f1fbb72fGustav Sennton        }
1202ed6fee15c85ff991f64ecfa8c1c4738e0fdf9b6Gustav Sennton    }
1212ed6fee15c85ff991f64ecfa8c1c4738e0fdf9b6Gustav Sennton
1222ed6fee15c85ff991f64ecfa8c1c4738e0fdf9b6Gustav Sennton    private static String getWebViewLibrary(ApplicationInfo ai) {
1232ed6fee15c85ff991f64ecfa8c1c4738e0fdf9b6Gustav Sennton        if (ai.metaData != null)
1242ed6fee15c85ff991f64ecfa8c1c4738e0fdf9b6Gustav Sennton            return ai.metaData.getString("com.android.webview.WebViewLibrary");
1252ed6fee15c85ff991f64ecfa8c1c4738e0fdf9b6Gustav Sennton        return null;
126dc00a84af15ff3594a6dfa512be21095bf9fee82Ben Murdoch    }
127dc00a84af15ff3594a6dfa512be21095bf9fee82Ben Murdoch
12884392d74fef177a87bc96a255761daf39569e726Torne (Richard Coles)    public static PackageInfo getLoadedPackageInfo() {
12984392d74fef177a87bc96a255761daf39569e726Torne (Richard Coles)        return sPackageInfo;
13084392d74fef177a87bc96a255761daf39569e726Torne (Richard Coles)    }
13184392d74fef177a87bc96a255761daf39569e726Torne (Richard Coles)
13285edb6c6bff62e163e4490951ec49a958c63fad0Gustav Sennton    /**
13385edb6c6bff62e163e4490951ec49a958c63fad0Gustav Sennton     * Load the native library for the given package name iff that package
134d9730182212b157083321ea4e2209182f1fbb72fGustav Sennton     * name is the same as the one providing the webview.
13585edb6c6bff62e163e4490951ec49a958c63fad0Gustav Sennton     */
13685edb6c6bff62e163e4490951ec49a958c63fad0Gustav Sennton    public static int loadWebViewNativeLibraryFromPackage(String packageName) {
137d9730182212b157083321ea4e2209182f1fbb72fGustav Sennton        sPackageInfo = fetchPackageInfo();
13885edb6c6bff62e163e4490951ec49a958c63fad0Gustav Sennton        if (packageName != null && packageName.equals(sPackageInfo.packageName)) {
13985edb6c6bff62e163e4490951ec49a958c63fad0Gustav Sennton            return loadNativeLibrary();
14085edb6c6bff62e163e4490951ec49a958c63fad0Gustav Sennton        }
14185edb6c6bff62e163e4490951ec49a958c63fad0Gustav Sennton        return LIBLOAD_WRONG_PACKAGE_NAME;
14285edb6c6bff62e163e4490951ec49a958c63fad0Gustav Sennton    }
14385edb6c6bff62e163e4490951ec49a958c63fad0Gustav Sennton
1449f9d34552f53c534141584a5ad4a8a49ad7939dcJohn Reck    static WebViewFactoryProvider getProvider() {
1459f9d34552f53c534141584a5ad4a8a49ad7939dcJohn Reck        synchronized (sProviderLock) {
1469f9d34552f53c534141584a5ad4a8a49ad7939dcJohn Reck            // For now the main purpose of this function (and the factory abstraction) is to keep
147d892afc88d3c67a7fe1c9550bfa7a452051d031dTorne (Richard Coles)            // us honest and minimize usage of WebView internals when binding the proxy.
1489f9d34552f53c534141584a5ad4a8a49ad7939dcJohn Reck            if (sProviderInstance != null) return sProviderInstance;
149d3101b1d300f5942fdb7dfa323dc8830c4edc007Jonathan Dixon
15085844916b8a7cc7f6aabc6c37af7380a4c000bcbJeff Sharkey            final int uid = android.os.Process.myUid();
15185844916b8a7cc7f6aabc6c37af7380a4c000bcbJeff Sharkey            if (uid == android.os.Process.ROOT_UID || uid == android.os.Process.SYSTEM_UID) {
15285844916b8a7cc7f6aabc6c37af7380a4c000bcbJeff Sharkey                throw new UnsupportedOperationException(
15385844916b8a7cc7f6aabc6c37af7380a4c000bcbJeff Sharkey                        "For security reasons, WebView is not allowed in privileged processes");
15485844916b8a7cc7f6aabc6c37af7380a4c000bcbJeff Sharkey            }
15585844916b8a7cc7f6aabc6c37af7380a4c000bcbJeff Sharkey
1563822882b32d9b1b803aaff9b657a91d680f1d0f9Torne (Richard Coles)            Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "WebViewFactory.getProvider()");
15703ce9b3e69f1eec85e7e7cbfd65bb9093e74cea8Torne (Richard Coles)            try {
158a8366e78b58aeb392a9dcc7301183e881d99c783Gustav Sennton                Class<WebViewFactoryProvider> providerClass = getProviderClass();
1593822882b32d9b1b803aaff9b657a91d680f1d0f9Torne (Richard Coles)
1603822882b32d9b1b803aaff9b657a91d680f1d0f9Torne (Richard Coles)                StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
1613822882b32d9b1b803aaff9b657a91d680f1d0f9Torne (Richard Coles)                Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "providerClass.newInstance()");
1623822882b32d9b1b803aaff9b657a91d680f1d0f9Torne (Richard Coles)                try {
1631ea39b350c2a1c2595ab3b7c4ba3ab8a3b029315Ignacio Solla                    sProviderInstance = providerClass.getConstructor(WebViewDelegate.class)
1641ea39b350c2a1c2595ab3b7c4ba3ab8a3b029315Ignacio Solla                            .newInstance(new WebViewDelegate());
1653822882b32d9b1b803aaff9b657a91d680f1d0f9Torne (Richard Coles)                    if (DEBUG) Log.v(LOGTAG, "Loaded provider: " + sProviderInstance);
1663822882b32d9b1b803aaff9b657a91d680f1d0f9Torne (Richard Coles)                    return sProviderInstance;
1673822882b32d9b1b803aaff9b657a91d680f1d0f9Torne (Richard Coles)                } catch (Exception e) {
1683822882b32d9b1b803aaff9b657a91d680f1d0f9Torne (Richard Coles)                    Log.e(LOGTAG, "error instantiating provider", e);
1693822882b32d9b1b803aaff9b657a91d680f1d0f9Torne (Richard Coles)                    throw new AndroidRuntimeException(e);
1703822882b32d9b1b803aaff9b657a91d680f1d0f9Torne (Richard Coles)                } finally {
1713822882b32d9b1b803aaff9b657a91d680f1d0f9Torne (Richard Coles)                    Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW);
1723822882b32d9b1b803aaff9b657a91d680f1d0f9Torne (Richard Coles)                    StrictMode.setThreadPolicy(oldPolicy);
1733822882b32d9b1b803aaff9b657a91d680f1d0f9Torne (Richard Coles)                }
17403ce9b3e69f1eec85e7e7cbfd65bb9093e74cea8Torne (Richard Coles)            } finally {
1753822882b32d9b1b803aaff9b657a91d680f1d0f9Torne (Richard Coles)                Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW);
176e09e976dad1d974ca28381451b0bbbeafbb872d5Ben Murdoch            }
177d3101b1d300f5942fdb7dfa323dc8830c4edc007Jonathan Dixon        }
178d3101b1d300f5942fdb7dfa323dc8830c4edc007Jonathan Dixon    }
179d3101b1d300f5942fdb7dfa323dc8830c4edc007Jonathan Dixon
180a8366e78b58aeb392a9dcc7301183e881d99c783Gustav Sennton    private static Class<WebViewFactoryProvider> getProviderClass() {
181a8366e78b58aeb392a9dcc7301183e881d99c783Gustav Sennton        try {
182a8366e78b58aeb392a9dcc7301183e881d99c783Gustav Sennton            // First fetch the package info so we can log the webview package version.
183d9730182212b157083321ea4e2209182f1fbb72fGustav Sennton            sPackageInfo = fetchPackageInfo();
184a8366e78b58aeb392a9dcc7301183e881d99c783Gustav Sennton            Log.i(LOGTAG, "Loading " + sPackageInfo.packageName + " version " +
185a8366e78b58aeb392a9dcc7301183e881d99c783Gustav Sennton                sPackageInfo.versionName + " (code " + sPackageInfo.versionCode + ")");
186a8366e78b58aeb392a9dcc7301183e881d99c783Gustav Sennton
187a8366e78b58aeb392a9dcc7301183e881d99c783Gustav Sennton            Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "WebViewFactory.loadNativeLibrary()");
188a8366e78b58aeb392a9dcc7301183e881d99c783Gustav Sennton            loadNativeLibrary();
189a8366e78b58aeb392a9dcc7301183e881d99c783Gustav Sennton            Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW);
190a8366e78b58aeb392a9dcc7301183e881d99c783Gustav Sennton
191a8366e78b58aeb392a9dcc7301183e881d99c783Gustav Sennton            Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "WebViewFactory.getChromiumProviderClass()");
192a8366e78b58aeb392a9dcc7301183e881d99c783Gustav Sennton            try {
193a8366e78b58aeb392a9dcc7301183e881d99c783Gustav Sennton                return getChromiumProviderClass();
194a8366e78b58aeb392a9dcc7301183e881d99c783Gustav Sennton            } catch (ClassNotFoundException e) {
195a8366e78b58aeb392a9dcc7301183e881d99c783Gustav Sennton                Log.e(LOGTAG, "error loading provider", e);
196a8366e78b58aeb392a9dcc7301183e881d99c783Gustav Sennton                throw new AndroidRuntimeException(e);
197a8366e78b58aeb392a9dcc7301183e881d99c783Gustav Sennton            } finally {
198a8366e78b58aeb392a9dcc7301183e881d99c783Gustav Sennton                Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW);
199a8366e78b58aeb392a9dcc7301183e881d99c783Gustav Sennton            }
200a8366e78b58aeb392a9dcc7301183e881d99c783Gustav Sennton        } catch (MissingWebViewPackageException e) {
201a8366e78b58aeb392a9dcc7301183e881d99c783Gustav Sennton            // If the package doesn't exist, then try loading the null WebView instead.
202a8366e78b58aeb392a9dcc7301183e881d99c783Gustav Sennton            // If that succeeds, then this is a device without WebView support; if it fails then
203a8366e78b58aeb392a9dcc7301183e881d99c783Gustav Sennton            // swallow the failure, complain that the real WebView is missing and rethrow the
204a8366e78b58aeb392a9dcc7301183e881d99c783Gustav Sennton            // original exception.
205a8366e78b58aeb392a9dcc7301183e881d99c783Gustav Sennton            try {
206a8366e78b58aeb392a9dcc7301183e881d99c783Gustav Sennton                return (Class<WebViewFactoryProvider>) Class.forName(NULL_WEBVIEW_FACTORY);
207a8366e78b58aeb392a9dcc7301183e881d99c783Gustav Sennton            } catch (ClassNotFoundException e2) {
208a8366e78b58aeb392a9dcc7301183e881d99c783Gustav Sennton                // Ignore.
209a8366e78b58aeb392a9dcc7301183e881d99c783Gustav Sennton            }
210a8366e78b58aeb392a9dcc7301183e881d99c783Gustav Sennton            Log.e(LOGTAG, "Chromium WebView package does not exist", e);
211a8366e78b58aeb392a9dcc7301183e881d99c783Gustav Sennton            throw new AndroidRuntimeException(e);
212a8366e78b58aeb392a9dcc7301183e881d99c783Gustav Sennton        }
213a8366e78b58aeb392a9dcc7301183e881d99c783Gustav Sennton    }
214a8366e78b58aeb392a9dcc7301183e881d99c783Gustav Sennton
215a8366e78b58aeb392a9dcc7301183e881d99c783Gustav Sennton    // throws MissingWebViewPackageException
216a8366e78b58aeb392a9dcc7301183e881d99c783Gustav Sennton    private static Class<WebViewFactoryProvider> getChromiumProviderClass()
217a8366e78b58aeb392a9dcc7301183e881d99c783Gustav Sennton            throws ClassNotFoundException {
21863d3d8a458cfc124ebd183994d3d152d3b06c1d8Marcin Kosiba        Application initialApplication = AppGlobals.getInitialApplication();
2190e04bcfbdc1845c931b45b3498aef438b944e961Ben Murdoch        try {
2200606cd572ad345fb2c40456509feac626c68dee3Torne (Richard Coles)            // Construct a package context to load the Java code into the current app.
2212ed6fee15c85ff991f64ecfa8c1c4738e0fdf9b6Gustav Sennton            Context webViewContext = initialApplication.createPackageContext(
222d9730182212b157083321ea4e2209182f1fbb72fGustav Sennton                    sPackageInfo.packageName,
223d9730182212b157083321ea4e2209182f1fbb72fGustav Sennton                    Context.CONTEXT_INCLUDE_CODE | Context.CONTEXT_IGNORE_SECURITY);
22463d3d8a458cfc124ebd183994d3d152d3b06c1d8Marcin Kosiba            initialApplication.getAssets().addAssetPath(
22563d3d8a458cfc124ebd183994d3d152d3b06c1d8Marcin Kosiba                    webViewContext.getApplicationInfo().sourceDir);
2266c778cebc73e7eb76510f6e2183d804b8c07082bTorne (Richard Coles)            ClassLoader clazzLoader = webViewContext.getClassLoader();
2273822882b32d9b1b803aaff9b657a91d680f1d0f9Torne (Richard Coles)            Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "Class.forName()");
2283822882b32d9b1b803aaff9b657a91d680f1d0f9Torne (Richard Coles)            try {
2293822882b32d9b1b803aaff9b657a91d680f1d0f9Torne (Richard Coles)                return (Class<WebViewFactoryProvider>) Class.forName(CHROMIUM_WEBVIEW_FACTORY, true,
2303822882b32d9b1b803aaff9b657a91d680f1d0f9Torne (Richard Coles)                                                                     clazzLoader);
2313822882b32d9b1b803aaff9b657a91d680f1d0f9Torne (Richard Coles)            } finally {
2323822882b32d9b1b803aaff9b657a91d680f1d0f9Torne (Richard Coles)                Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW);
2333822882b32d9b1b803aaff9b657a91d680f1d0f9Torne (Richard Coles)            }
2346c778cebc73e7eb76510f6e2183d804b8c07082bTorne (Richard Coles)        } catch (PackageManager.NameNotFoundException e) {
235a8366e78b58aeb392a9dcc7301183e881d99c783Gustav Sennton            throw new MissingWebViewPackageException(e);
2360e04bcfbdc1845c931b45b3498aef438b944e961Ben Murdoch        }
237d3101b1d300f5942fdb7dfa323dc8830c4edc007Jonathan Dixon    }
23808cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)
23908cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)    /**
24008cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)     * Perform any WebView loading preparations that must happen in the zygote.
24108cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)     * Currently, this means allocating address space to load the real JNI library later.
24208cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)     */
24308cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)    public static void prepareWebViewInZygote() {
24408cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)        try {
24508cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)            System.loadLibrary("webviewchromium_loader");
2465ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdoch            long addressSpaceToReserve =
2475ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdoch                    SystemProperties.getLong(CHROMIUM_WEBVIEW_VMSIZE_SIZE_PROPERTY,
2485ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdoch                    CHROMIUM_WEBVIEW_DEFAULT_VMSIZE_BYTES);
2495ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdoch            sAddressSpaceReserved = nativeReserveAddressSpace(addressSpaceToReserve);
2505ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdoch
25108cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)            if (sAddressSpaceReserved) {
2525ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdoch                if (DEBUG) {
2535ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdoch                    Log.v(LOGTAG, "address space reserved: " + addressSpaceToReserve + " bytes");
2545ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdoch                }
25508cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)            } else {
2565ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdoch                Log.e(LOGTAG, "reserving " + addressSpaceToReserve +
2575ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdoch                        " bytes of address space failed");
25808cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)            }
259810c052d9b117217152c2a609ccec056a2a61d1ePrimiano Tucci        } catch (Throwable t) {
26008cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)            // Log and discard errors at this stage as we must not crash the zygote.
261810c052d9b117217152c2a609ccec056a2a61d1ePrimiano Tucci            Log.e(LOGTAG, "error preparing native loader", t);
26208cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)        }
26308cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)    }
26408cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)
26508cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)    /**
26608cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)     * Perform any WebView loading preparations that must happen at boot from the system server,
2675ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdoch     * after the package manager has started or after an update to the webview is installed.
26808cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)     * This must be called in the system server.
26908cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)     * Currently, this means spawning the child processes which will create the relro files.
27008cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)     */
27108cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)    public static void prepareWebViewInSystemServer() {
2725ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdoch        String[] nativePaths = null;
2735ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdoch        try {
2745ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdoch            nativePaths = getWebViewNativeLibraryPaths();
27527cb0d22a839f9fc132ae6b4e7c059c75a1826e1Torne (Richard Coles)        } catch (Throwable t) {
27627cb0d22a839f9fc132ae6b4e7c059c75a1826e1Torne (Richard Coles)            // Log and discard errors at this stage as we must not crash the system server.
27727cb0d22a839f9fc132ae6b4e7c059c75a1826e1Torne (Richard Coles)            Log.e(LOGTAG, "error preparing webview native library", t);
2785ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdoch        }
2795ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdoch        prepareWebViewInSystemServer(nativePaths);
2805ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdoch    }
2815ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdoch
2825ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdoch    private static void prepareWebViewInSystemServer(String[] nativeLibraryPaths) {
28308cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)        if (DEBUG) Log.v(LOGTAG, "creating relro files");
2845ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdoch
2855ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdoch        // We must always trigger createRelRo regardless of the value of nativeLibraryPaths. Any
2865ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdoch        // unexpected values will be handled there to ensure that we trigger notifying any process
2875ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdoch        // waiting on relreo creation.
2885ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdoch        if (Build.SUPPORTED_32_BIT_ABIS.length > 0) {
2895ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdoch            if (DEBUG) Log.v(LOGTAG, "Create 32 bit relro");
2905ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdoch            createRelroFile(false /* is64Bit */, nativeLibraryPaths);
2915ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdoch        }
2925ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdoch
2935ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdoch        if (Build.SUPPORTED_64_BIT_ABIS.length > 0) {
2945ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdoch            if (DEBUG) Log.v(LOGTAG, "Create 64 bit relro");
2955ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdoch            createRelroFile(true /* is64Bit */, nativeLibraryPaths);
2965ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdoch        }
2975ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdoch    }
2985ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdoch
2995ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdoch    public static void onWebViewUpdateInstalled() {
3005ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdoch        String[] nativeLibs = null;
3015ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdoch        try {
3025ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdoch            nativeLibs = WebViewFactory.getWebViewNativeLibraryPaths();
30327cb0d22a839f9fc132ae6b4e7c059c75a1826e1Torne (Richard Coles)            if (nativeLibs != null) {
30427cb0d22a839f9fc132ae6b4e7c059c75a1826e1Torne (Richard Coles)                long newVmSize = 0L;
30527cb0d22a839f9fc132ae6b4e7c059c75a1826e1Torne (Richard Coles)
30627cb0d22a839f9fc132ae6b4e7c059c75a1826e1Torne (Richard Coles)                for (String path : nativeLibs) {
307b98082dcfb45a82d9b12dbf0d2f88acffe96a1c4Simon Baldwin                    if (path == null || TextUtils.isEmpty(path)) continue;
30827cb0d22a839f9fc132ae6b4e7c059c75a1826e1Torne (Richard Coles)                    if (DEBUG) Log.d(LOGTAG, "Checking file size of " + path);
30927cb0d22a839f9fc132ae6b4e7c059c75a1826e1Torne (Richard Coles)                    File f = new File(path);
31027cb0d22a839f9fc132ae6b4e7c059c75a1826e1Torne (Richard Coles)                    if (f.exists()) {
311b98082dcfb45a82d9b12dbf0d2f88acffe96a1c4Simon Baldwin                        newVmSize = Math.max(newVmSize, f.length());
312b98082dcfb45a82d9b12dbf0d2f88acffe96a1c4Simon Baldwin                        continue;
313b98082dcfb45a82d9b12dbf0d2f88acffe96a1c4Simon Baldwin                    }
314519919b0d4b9ebeb685ce9f3632078545792e408Simon Baldwin                    if (path.contains("!/")) {
315519919b0d4b9ebeb685ce9f3632078545792e408Simon Baldwin                        String[] split = TextUtils.split(path, "!/");
316b98082dcfb45a82d9b12dbf0d2f88acffe96a1c4Simon Baldwin                        if (split.length == 2) {
317c52839277b8714d150a9fe276b6ba3fa8a0cbf38Torne (Richard Coles)                            try (ZipFile z = new ZipFile(split[0])) {
318b98082dcfb45a82d9b12dbf0d2f88acffe96a1c4Simon Baldwin                                ZipEntry e = z.getEntry(split[1]);
319b98082dcfb45a82d9b12dbf0d2f88acffe96a1c4Simon Baldwin                                if (e != null && e.getMethod() == ZipEntry.STORED) {
320b98082dcfb45a82d9b12dbf0d2f88acffe96a1c4Simon Baldwin                                    newVmSize = Math.max(newVmSize, e.getSize());
321b98082dcfb45a82d9b12dbf0d2f88acffe96a1c4Simon Baldwin                                    continue;
322b98082dcfb45a82d9b12dbf0d2f88acffe96a1c4Simon Baldwin                                }
323b98082dcfb45a82d9b12dbf0d2f88acffe96a1c4Simon Baldwin                            }
324b98082dcfb45a82d9b12dbf0d2f88acffe96a1c4Simon Baldwin                            catch (IOException e) {
325b98082dcfb45a82d9b12dbf0d2f88acffe96a1c4Simon Baldwin                                Log.e(LOGTAG, "error reading APK file " + split[0] + ", ", e);
326b98082dcfb45a82d9b12dbf0d2f88acffe96a1c4Simon Baldwin                            }
32727cb0d22a839f9fc132ae6b4e7c059c75a1826e1Torne (Richard Coles)                        }
3285ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdoch                    }
329b98082dcfb45a82d9b12dbf0d2f88acffe96a1c4Simon Baldwin                    Log.e(LOGTAG, "error sizing load for " + path);
3305ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdoch                }
3315ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdoch
33227cb0d22a839f9fc132ae6b4e7c059c75a1826e1Torne (Richard Coles)                if (DEBUG) {
33327cb0d22a839f9fc132ae6b4e7c059c75a1826e1Torne (Richard Coles)                    Log.v(LOGTAG, "Based on library size, need " + newVmSize +
33427cb0d22a839f9fc132ae6b4e7c059c75a1826e1Torne (Richard Coles)                            " bytes of address space.");
33527cb0d22a839f9fc132ae6b4e7c059c75a1826e1Torne (Richard Coles)                }
33627cb0d22a839f9fc132ae6b4e7c059c75a1826e1Torne (Richard Coles)                // The required memory can be larger than the file on disk (due to .bss), and an
33727cb0d22a839f9fc132ae6b4e7c059c75a1826e1Torne (Richard Coles)                // upgraded version of the library will likely be larger, so always attempt to
33827cb0d22a839f9fc132ae6b4e7c059c75a1826e1Torne (Richard Coles)                // reserve twice as much as we think to allow for the library to grow during this
33927cb0d22a839f9fc132ae6b4e7c059c75a1826e1Torne (Richard Coles)                // boot cycle.
34027cb0d22a839f9fc132ae6b4e7c059c75a1826e1Torne (Richard Coles)                newVmSize = Math.max(2 * newVmSize, CHROMIUM_WEBVIEW_DEFAULT_VMSIZE_BYTES);
34127cb0d22a839f9fc132ae6b4e7c059c75a1826e1Torne (Richard Coles)                Log.d(LOGTAG, "Setting new address space to " + newVmSize);
34227cb0d22a839f9fc132ae6b4e7c059c75a1826e1Torne (Richard Coles)                SystemProperties.set(CHROMIUM_WEBVIEW_VMSIZE_SIZE_PROPERTY,
34327cb0d22a839f9fc132ae6b4e7c059c75a1826e1Torne (Richard Coles)                        Long.toString(newVmSize));
3445ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdoch            }
34527cb0d22a839f9fc132ae6b4e7c059c75a1826e1Torne (Richard Coles)        } catch (Throwable t) {
34627cb0d22a839f9fc132ae6b4e7c059c75a1826e1Torne (Richard Coles)            // Log and discard errors at this stage as we must not crash the system server.
34727cb0d22a839f9fc132ae6b4e7c059c75a1826e1Torne (Richard Coles)            Log.e(LOGTAG, "error preparing webview native library", t);
34808cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)        }
3495ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdoch        prepareWebViewInSystemServer(nativeLibs);
35008cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)    }
35108cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)
352a8366e78b58aeb392a9dcc7301183e881d99c783Gustav Sennton    // throws MissingWebViewPackageException
353b98082dcfb45a82d9b12dbf0d2f88acffe96a1c4Simon Baldwin    private static String getLoadFromApkPath(String apkPath,
354b98082dcfb45a82d9b12dbf0d2f88acffe96a1c4Simon Baldwin                                             String[] abiList,
355b98082dcfb45a82d9b12dbf0d2f88acffe96a1c4Simon Baldwin                                             String nativeLibFileName) {
356b98082dcfb45a82d9b12dbf0d2f88acffe96a1c4Simon Baldwin        // Search the APK for a native library conforming to a listed ABI.
357c52839277b8714d150a9fe276b6ba3fa8a0cbf38Torne (Richard Coles)        try (ZipFile z = new ZipFile(apkPath)) {
358b98082dcfb45a82d9b12dbf0d2f88acffe96a1c4Simon Baldwin            for (String abi : abiList) {
359b98082dcfb45a82d9b12dbf0d2f88acffe96a1c4Simon Baldwin                final String entry = "lib/" + abi + "/" + nativeLibFileName;
360b98082dcfb45a82d9b12dbf0d2f88acffe96a1c4Simon Baldwin                ZipEntry e = z.getEntry(entry);
361b98082dcfb45a82d9b12dbf0d2f88acffe96a1c4Simon Baldwin                if (e != null && e.getMethod() == ZipEntry.STORED) {
362b98082dcfb45a82d9b12dbf0d2f88acffe96a1c4Simon Baldwin                    // Return a path formatted for dlopen() load from APK.
363519919b0d4b9ebeb685ce9f3632078545792e408Simon Baldwin                    return apkPath + "!/" + entry;
364b98082dcfb45a82d9b12dbf0d2f88acffe96a1c4Simon Baldwin                }
365b98082dcfb45a82d9b12dbf0d2f88acffe96a1c4Simon Baldwin            }
366b98082dcfb45a82d9b12dbf0d2f88acffe96a1c4Simon Baldwin        } catch (IOException e) {
367b98082dcfb45a82d9b12dbf0d2f88acffe96a1c4Simon Baldwin            throw new MissingWebViewPackageException(e);
368b98082dcfb45a82d9b12dbf0d2f88acffe96a1c4Simon Baldwin        }
369b98082dcfb45a82d9b12dbf0d2f88acffe96a1c4Simon Baldwin        return "";
370b98082dcfb45a82d9b12dbf0d2f88acffe96a1c4Simon Baldwin    }
371b98082dcfb45a82d9b12dbf0d2f88acffe96a1c4Simon Baldwin
372b98082dcfb45a82d9b12dbf0d2f88acffe96a1c4Simon Baldwin    // throws MissingWebViewPackageException
373a8366e78b58aeb392a9dcc7301183e881d99c783Gustav Sennton    private static String[] getWebViewNativeLibraryPaths() {
3742ed6fee15c85ff991f64ecfa8c1c4738e0fdf9b6Gustav Sennton        ApplicationInfo ai = getWebViewApplicationInfo();
3752ed6fee15c85ff991f64ecfa8c1c4738e0fdf9b6Gustav Sennton        final String NATIVE_LIB_FILE_NAME = getWebViewLibrary(ai);
3761b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucci
3771b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucci        String path32;
3781b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucci        String path64;
3791b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucci        boolean primaryArchIs64bit = VMRuntime.is64BitAbi(ai.primaryCpuAbi);
3801b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucci        if (!TextUtils.isEmpty(ai.secondaryCpuAbi)) {
3811b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucci            // Multi-arch case.
3821b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucci            if (primaryArchIs64bit) {
3831b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucci                // Primary arch: 64-bit, secondary: 32-bit.
3841b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucci                path64 = ai.nativeLibraryDir;
3851b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucci                path32 = ai.secondaryNativeLibraryDir;
3861b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucci            } else {
3871b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucci                // Primary arch: 32-bit, secondary: 64-bit.
3881b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucci                path64 = ai.secondaryNativeLibraryDir;
3891b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucci                path32 = ai.nativeLibraryDir;
3901b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucci            }
3911b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucci        } else if (primaryArchIs64bit) {
3921b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucci            // Single-arch 64-bit.
3931b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucci            path64 = ai.nativeLibraryDir;
3941b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucci            path32 = "";
3951b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucci        } else {
3961b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucci            // Single-arch 32-bit.
3971b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucci            path32 = ai.nativeLibraryDir;
3981b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucci            path64 = "";
3991b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucci        }
400b98082dcfb45a82d9b12dbf0d2f88acffe96a1c4Simon Baldwin
401b98082dcfb45a82d9b12dbf0d2f88acffe96a1c4Simon Baldwin        // Form the full paths to the extracted native libraries.
402b98082dcfb45a82d9b12dbf0d2f88acffe96a1c4Simon Baldwin        // If libraries were not extracted, try load from APK paths instead.
403b98082dcfb45a82d9b12dbf0d2f88acffe96a1c4Simon Baldwin        if (!TextUtils.isEmpty(path32)) {
404b98082dcfb45a82d9b12dbf0d2f88acffe96a1c4Simon Baldwin            path32 += "/" + NATIVE_LIB_FILE_NAME;
405b98082dcfb45a82d9b12dbf0d2f88acffe96a1c4Simon Baldwin            File f = new File(path32);
406b98082dcfb45a82d9b12dbf0d2f88acffe96a1c4Simon Baldwin            if (!f.exists()) {
407b98082dcfb45a82d9b12dbf0d2f88acffe96a1c4Simon Baldwin                path32 = getLoadFromApkPath(ai.sourceDir,
408b98082dcfb45a82d9b12dbf0d2f88acffe96a1c4Simon Baldwin                                            Build.SUPPORTED_32_BIT_ABIS,
409b98082dcfb45a82d9b12dbf0d2f88acffe96a1c4Simon Baldwin                                            NATIVE_LIB_FILE_NAME);
410b98082dcfb45a82d9b12dbf0d2f88acffe96a1c4Simon Baldwin            }
411b98082dcfb45a82d9b12dbf0d2f88acffe96a1c4Simon Baldwin        }
412b98082dcfb45a82d9b12dbf0d2f88acffe96a1c4Simon Baldwin        if (!TextUtils.isEmpty(path64)) {
413b98082dcfb45a82d9b12dbf0d2f88acffe96a1c4Simon Baldwin            path64 += "/" + NATIVE_LIB_FILE_NAME;
414b98082dcfb45a82d9b12dbf0d2f88acffe96a1c4Simon Baldwin            File f = new File(path64);
415b98082dcfb45a82d9b12dbf0d2f88acffe96a1c4Simon Baldwin            if (!f.exists()) {
416b98082dcfb45a82d9b12dbf0d2f88acffe96a1c4Simon Baldwin                path64 = getLoadFromApkPath(ai.sourceDir,
417b98082dcfb45a82d9b12dbf0d2f88acffe96a1c4Simon Baldwin                                            Build.SUPPORTED_64_BIT_ABIS,
418b98082dcfb45a82d9b12dbf0d2f88acffe96a1c4Simon Baldwin                                            NATIVE_LIB_FILE_NAME);
419b98082dcfb45a82d9b12dbf0d2f88acffe96a1c4Simon Baldwin            }
420b98082dcfb45a82d9b12dbf0d2f88acffe96a1c4Simon Baldwin        }
421b98082dcfb45a82d9b12dbf0d2f88acffe96a1c4Simon Baldwin
422b98082dcfb45a82d9b12dbf0d2f88acffe96a1c4Simon Baldwin        if (DEBUG) Log.v(LOGTAG, "Native 32-bit lib: " + path32 + ", 64-bit lib: " + path64);
4231b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucci        return new String[] { path32, path64 };
4241b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucci    }
4251b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucci
4265ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdoch    private static void createRelroFile(final boolean is64Bit, String[] nativeLibraryPaths) {
4271b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucci        final String abi =
4281b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucci                is64Bit ? Build.SUPPORTED_64_BIT_ABIS[0] : Build.SUPPORTED_32_BIT_ABIS[0];
429810c052d9b117217152c2a609ccec056a2a61d1ePrimiano Tucci
430810c052d9b117217152c2a609ccec056a2a61d1ePrimiano Tucci        // crashHandler is invoked by the ActivityManagerService when the isolated process crashes.
431810c052d9b117217152c2a609ccec056a2a61d1ePrimiano Tucci        Runnable crashHandler = new Runnable() {
432810c052d9b117217152c2a609ccec056a2a61d1ePrimiano Tucci            @Override
433810c052d9b117217152c2a609ccec056a2a61d1ePrimiano Tucci            public void run() {
434810c052d9b117217152c2a609ccec056a2a61d1ePrimiano Tucci                try {
4351b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucci                    Log.e(LOGTAG, "relro file creator for " + abi + " crashed. Proceeding without");
436810c052d9b117217152c2a609ccec056a2a61d1ePrimiano Tucci                    getUpdateService().notifyRelroCreationCompleted(is64Bit, false);
437810c052d9b117217152c2a609ccec056a2a61d1ePrimiano Tucci                } catch (RemoteException e) {
438810c052d9b117217152c2a609ccec056a2a61d1ePrimiano Tucci                    Log.e(LOGTAG, "Cannot reach WebViewUpdateService. " + e.getMessage());
439810c052d9b117217152c2a609ccec056a2a61d1ePrimiano Tucci                }
440810c052d9b117217152c2a609ccec056a2a61d1ePrimiano Tucci            }
441810c052d9b117217152c2a609ccec056a2a61d1ePrimiano Tucci        };
442810c052d9b117217152c2a609ccec056a2a61d1ePrimiano Tucci
44308cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)        try {
4445ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdoch            if (nativeLibraryPaths == null
4455ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdoch                    || nativeLibraryPaths[0] == null || nativeLibraryPaths[1] == null) {
4465ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdoch                throw new IllegalArgumentException(
4475ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdoch                        "Native library paths to the WebView RelRo process must not be null!");
4485ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdoch            }
449161536b5970ba5ab43233e7695ef69ba2bb804f4Primiano Tucci            int pid = LocalServices.getService(ActivityManagerInternal.class).startIsolatedProcess(
4505ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdoch                    RelroFileCreator.class.getName(), nativeLibraryPaths, "WebViewLoader-" + abi, abi,
451810c052d9b117217152c2a609ccec056a2a61d1ePrimiano Tucci                    Process.SHARED_RELRO_UID, crashHandler);
452e76e81a227a29db5223d231ec88ecb02fa4d6835Primiano Tucci            if (pid <= 0) throw new Exception("Failed to start the relro file creator process");
453810c052d9b117217152c2a609ccec056a2a61d1ePrimiano Tucci        } catch (Throwable t) {
45408cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)            // Log and discard errors as we must not crash the system server.
455810c052d9b117217152c2a609ccec056a2a61d1ePrimiano Tucci            Log.e(LOGTAG, "error starting relro file creator for abi " + abi, t);
456810c052d9b117217152c2a609ccec056a2a61d1ePrimiano Tucci            crashHandler.run();
45708cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)        }
45808cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)    }
45908cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)
46008cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)    private static class RelroFileCreator {
46108cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)        // Called in an unprivileged child process to create the relro file.
46208cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)        public static void main(String[] args) {
463161536b5970ba5ab43233e7695ef69ba2bb804f4Primiano Tucci            boolean result = false;
464161536b5970ba5ab43233e7695ef69ba2bb804f4Primiano Tucci            boolean is64Bit = VMRuntime.getRuntime().is64Bit();
4651b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucci            try{
4661b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucci                if (args.length != 2 || args[0] == null || args[1] == null) {
4671b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucci                    Log.e(LOGTAG, "Invalid RelroFileCreator args: " + Arrays.toString(args));
4681b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucci                    return;
4691b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucci                }
4701b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucci                Log.v(LOGTAG, "RelroFileCreator (64bit = " + is64Bit + "), " +
4711b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucci                        " 32-bit lib: " + args[0] + ", 64-bit lib: " + args[1]);
4721b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucci                if (!sAddressSpaceReserved) {
4731b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucci                    Log.e(LOGTAG, "can't create relro file; address space not reserved");
4741b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucci                    return;
4751b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucci                }
476161536b5970ba5ab43233e7695ef69ba2bb804f4Primiano Tucci                result = nativeCreateRelroFile(args[0] /* path32 */,
477161536b5970ba5ab43233e7695ef69ba2bb804f4Primiano Tucci                                               args[1] /* path64 */,
478161536b5970ba5ab43233e7695ef69ba2bb804f4Primiano Tucci                                               CHROMIUM_WEBVIEW_NATIVE_RELRO_32,
479161536b5970ba5ab43233e7695ef69ba2bb804f4Primiano Tucci                                               CHROMIUM_WEBVIEW_NATIVE_RELRO_64);
480e76e81a227a29db5223d231ec88ecb02fa4d6835Primiano Tucci                if (result && DEBUG) Log.v(LOGTAG, "created relro file");
481161536b5970ba5ab43233e7695ef69ba2bb804f4Primiano Tucci            } finally {
482161536b5970ba5ab43233e7695ef69ba2bb804f4Primiano Tucci                // We must do our best to always notify the update service, even if something fails.
4831b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucci                try {
4841b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucci                    getUpdateService().notifyRelroCreationCompleted(is64Bit, result);
4851b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucci                } catch (RemoteException e) {
4861b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucci                    Log.e(LOGTAG, "error notifying update service", e);
4871b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucci                }
488161536b5970ba5ab43233e7695ef69ba2bb804f4Primiano Tucci
489161536b5970ba5ab43233e7695ef69ba2bb804f4Primiano Tucci                if (!result) Log.e(LOGTAG, "failed to create relro file");
490161536b5970ba5ab43233e7695ef69ba2bb804f4Primiano Tucci
4911b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucci                // Must explicitly exit or else this process will just sit around after we return.
4921b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucci                System.exit(0);
4931b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucci            }
49408cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)        }
49508cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)    }
49608cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)
49785edb6c6bff62e163e4490951ec49a958c63fad0Gustav Sennton    private static int loadNativeLibrary() {
49808cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)        if (!sAddressSpaceReserved) {
49908cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)            Log.e(LOGTAG, "can't load with relro file; address space not reserved");
50085edb6c6bff62e163e4490951ec49a958c63fad0Gustav Sennton            return LIBLOAD_ADDRESS_SPACE_NOT_RESERVED;
50108cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)        }
50208cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)
50308cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)        try {
50408cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)            getUpdateService().waitForRelroCreationCompleted(VMRuntime.getRuntime().is64Bit());
50508cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)        } catch (RemoteException e) {
50608cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)            Log.e(LOGTAG, "error waiting for relro creation, proceeding without", e);
50785edb6c6bff62e163e4490951ec49a958c63fad0Gustav Sennton            return LIBLOAD_FAILED_WAITING_FOR_RELRO;
50808cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)        }
50908cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)
5101b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucci        try {
5111b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucci            String[] args = getWebViewNativeLibraryPaths();
51285edb6c6bff62e163e4490951ec49a958c63fad0Gustav Sennton            int result = nativeLoadWithRelroFile(args[0] /* path32 */,
5131b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucci                                                     args[1] /* path64 */,
5141b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucci                                                     CHROMIUM_WEBVIEW_NATIVE_RELRO_32,
5151b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucci                                                     CHROMIUM_WEBVIEW_NATIVE_RELRO_64);
51685edb6c6bff62e163e4490951ec49a958c63fad0Gustav Sennton            if (result != LIBLOAD_SUCCESS) {
5171b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucci                Log.w(LOGTAG, "failed to load with relro file, proceeding without");
5181b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucci            } else if (DEBUG) {
5191b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucci                Log.v(LOGTAG, "loaded with relro file");
5201b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucci            }
52185edb6c6bff62e163e4490951ec49a958c63fad0Gustav Sennton            return result;
522a8366e78b58aeb392a9dcc7301183e881d99c783Gustav Sennton        } catch (MissingWebViewPackageException e) {
5231b7977b608cd07366a1708aba36d48203f85bbbdPrimiano Tucci            Log.e(LOGTAG, "Failed to list WebView package libraries for loadNativeLibrary", e);
52485edb6c6bff62e163e4490951ec49a958c63fad0Gustav Sennton            return LIBLOAD_FAILED_LISTING_WEBVIEW_PACKAGES;
52508cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)        }
52608cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)    }
52708cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)
52808cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)    private static IWebViewUpdateService getUpdateService() {
52908cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)        return IWebViewUpdateService.Stub.asInterface(ServiceManager.getService("webviewupdate"));
53008cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)    }
53108cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)
5325ced502fba5a69dc1d2e55b3d7e5fd429280d6aeBen Murdoch    private static native boolean nativeReserveAddressSpace(long addressSpaceToReserve);
53308cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)    private static native boolean nativeCreateRelroFile(String lib32, String lib64,
53408cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)                                                        String relro32, String relro64);
53585edb6c6bff62e163e4490951ec49a958c63fad0Gustav Sennton    private static native int nativeLoadWithRelroFile(String lib32, String lib64,
53608cfaf672604422dd355d6703aec78f3aa5ee74eTorne (Richard Coles)                                                          String relro32, String relro64);
537d3101b1d300f5942fdb7dfa323dc8830c4edc007Jonathan Dixon}
538