blob: d884f199dd863a4a4762351133e48cfd39ded97b [file] [log] [blame]
Jonathan Dixond3101b12012-04-12 20:51:51 +01001/*
2 * Copyright (C) 2012 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.webkit;
18
Ignacio Solla451e3382014-11-10 10:35:54 +000019import android.annotation.SystemApi;
Primiano Tucci810c0522014-07-25 18:03:16 +010020import android.app.ActivityManagerInternal;
Torne (Richard Coles)6c778ce2014-07-17 14:14:48 -070021import android.app.AppGlobals;
Jeff Sharkey85844912014-11-13 16:20:38 -080022import android.app.Application;
Torne (Richard Coles)6c778ce2014-07-17 14:14:48 -070023import android.content.Context;
Gustav Senntonc83e3fa2016-02-18 12:19:13 +000024import android.content.Intent;
Primiano Tucci1b7977b2014-07-25 19:19:32 +010025import android.content.pm.ApplicationInfo;
Torne (Richard Coles)0606cd52014-08-05 16:12:09 +010026import android.content.pm.PackageInfo;
Torne (Richard Coles)6c778ce2014-07-17 14:14:48 -070027import android.content.pm.PackageManager;
Gustav Sennton6258dcd2015-10-30 19:25:37 +000028import android.content.res.XmlResourceParser;
Torne (Richard Coles)08cfaf62014-05-08 16:07:05 +010029import android.os.Build;
30import android.os.Process;
31import android.os.RemoteException;
32import android.os.ServiceManager;
Ben Murdoche09e9762012-07-19 14:48:13 +010033import android.os.StrictMode;
Ben Murdoch5ced5022014-07-28 15:57:00 +010034import android.os.SystemProperties;
Torne (Richard Coles)38228822014-08-13 17:11:45 +010035import android.os.Trace;
Gustav Sennton6258dcd2015-10-30 19:25:37 +000036import android.provider.Settings;
37import android.provider.Settings.Secure;
Primiano Tucci1b7977b2014-07-25 19:19:32 +010038import android.text.TextUtils;
Torne (Richard Coles)03ce9b32013-06-12 16:02:03 +010039import android.util.AndroidRuntimeException;
Jonathan Dixond3101b12012-04-12 20:51:51 +010040import android.util.Log;
Jeff Sharkey85844912014-11-13 16:20:38 -080041
Gustav Sennton6258dcd2015-10-30 19:25:37 +000042import com.android.internal.util.XmlUtils;
Primiano Tucci810c0522014-07-25 18:03:16 +010043import com.android.server.LocalServices;
Jeff Sharkey85844912014-11-13 16:20:38 -080044
Torne (Richard Coles)08cfaf62014-05-08 16:07:05 +010045import dalvik.system.VMRuntime;
46
47import java.io.File;
Simon Baldwinb98082dc2015-05-15 12:56:50 +010048import java.io.IOException;
Gustav Sennton6258dcd2015-10-30 19:25:37 +000049import java.util.ArrayList;
Primiano Tucci1b7977b2014-07-25 19:19:32 +010050import java.util.Arrays;
Gustav Sennton6258dcd2015-10-30 19:25:37 +000051import java.util.List;
Simon Baldwinb98082dc2015-05-15 12:56:50 +010052import java.util.zip.ZipEntry;
53import java.util.zip.ZipFile;
Torne (Richard Coles)08cfaf62014-05-08 16:07:05 +010054
Gustav Sennton6258dcd2015-10-30 19:25:37 +000055import org.xmlpull.v1.XmlPullParserException;
56
Jonathan Dixond3101b12012-04-12 20:51:51 +010057/**
58 * Top level factory, used creating all the main WebView implementation classes.
Jared Dukeb0e35842013-03-19 16:25:39 -070059 *
60 * @hide
Jonathan Dixond3101b12012-04-12 20:51:51 +010061 */
Ignacio Solla451e3382014-11-10 10:35:54 +000062@SystemApi
Jared Dukeb0e35842013-03-19 16:25:39 -070063public final class WebViewFactory {
Jonathan Dixona7eaa8e2013-07-25 19:52:47 -070064
Ben Murdoche09e9762012-07-19 14:48:13 +010065 private static final String CHROMIUM_WEBVIEW_FACTORY =
Torne (Richard Coles)a9bbd942012-10-24 11:59:22 +010066 "com.android.webview.chromium.WebViewChromiumFactoryProvider";
Jonathan Dixond3101b12012-04-12 20:51:51 +010067
Ben Murdoch0e04bcf2014-05-16 13:41:12 +010068 private static final String NULL_WEBVIEW_FACTORY =
69 "com.android.webview.nullwebview.NullWebViewFactoryProvider";
70
Torne (Richard Coles)08cfaf62014-05-08 16:07:05 +010071 private static final String CHROMIUM_WEBVIEW_NATIVE_RELRO_32 =
72 "/data/misc/shared_relro/libwebviewchromium32.relro";
73 private static final String CHROMIUM_WEBVIEW_NATIVE_RELRO_64 =
74 "/data/misc/shared_relro/libwebviewchromium64.relro";
75
Ben Murdoch5ced5022014-07-28 15:57:00 +010076 public static final String CHROMIUM_WEBVIEW_VMSIZE_SIZE_PROPERTY =
77 "persist.sys.webview.vmsize";
78 private static final long CHROMIUM_WEBVIEW_DEFAULT_VMSIZE_BYTES = 100 * 1024 * 1024;
Primiano Tucci1b7977b2014-07-25 19:19:32 +010079
Jonathan Dixond3101b12012-04-12 20:51:51 +010080 private static final String LOGTAG = "WebViewFactory";
81
82 private static final boolean DEBUG = false;
83
84 // Cache the factory both for efficiency, and ensure any one process gets all webviews from the
85 // same provider.
86 private static WebViewFactoryProvider sProviderInstance;
John Reck9f9d3452012-09-20 13:18:59 -070087 private static final Object sProviderLock = new Object();
Torne (Richard Coles)08cfaf62014-05-08 16:07:05 +010088 private static boolean sAddressSpaceReserved = false;
Torne (Richard Coles)84392d72014-08-14 16:43:18 +010089 private static PackageInfo sPackageInfo;
Jonathan Dixond3101b12012-04-12 20:51:51 +010090
Gustav Sennton85edb6c2015-04-15 11:54:20 +010091 // Error codes for loadWebViewNativeLibraryFromPackage
92 public static final int LIBLOAD_SUCCESS = 0;
93 public static final int LIBLOAD_WRONG_PACKAGE_NAME = 1;
94 public static final int LIBLOAD_ADDRESS_SPACE_NOT_RESERVED = 2;
Gustav Sennton6258dcd2015-10-30 19:25:37 +000095
96 // error codes for waiting for WebView preparation
Gustav Sennton85edb6c2015-04-15 11:54:20 +010097 public static final int LIBLOAD_FAILED_WAITING_FOR_RELRO = 3;
98 public static final int LIBLOAD_FAILED_LISTING_WEBVIEW_PACKAGES = 4;
99
100 // native relro loading error codes
101 public static final int LIBLOAD_FAILED_TO_OPEN_RELRO_FILE = 5;
102 public static final int LIBLOAD_FAILED_TO_LOAD_LIBRARY = 6;
103 public static final int LIBLOAD_FAILED_JNI_CALL = 7;
104
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000105 // more error codes for waiting for WebView preparation
Gustav Sennton26c82ff2016-03-11 13:06:40 +0000106 public static final int LIBLOAD_FAILED_WAITING_FOR_WEBVIEW_REASON_UNKNOWN = 8;
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000107
Torne (Richard Coles)1a904122016-03-14 13:45:55 +0000108 // error for namespace lookup
109 public static final int LIBLOAD_FAILED_TO_FIND_NAMESPACE = 10;
110
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000111 private static String getWebViewPreparationErrorReason(int error) {
112 switch (error) {
113 case LIBLOAD_FAILED_WAITING_FOR_RELRO:
114 return "Time out waiting for Relro files being created";
115 case LIBLOAD_FAILED_LISTING_WEBVIEW_PACKAGES:
116 return "No WebView installed";
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000117 case LIBLOAD_FAILED_WAITING_FOR_WEBVIEW_REASON_UNKNOWN:
118 return "Crashed for unknown reason";
119 }
120 return "Unknown";
121 }
122
123 /**
124 * @hide
125 */
126 public static class MissingWebViewPackageException extends AndroidRuntimeException {
Gustav Senntona8366e72015-04-17 11:24:07 +0100127 public MissingWebViewPackageException(String message) { super(message); }
128 public MissingWebViewPackageException(Exception e) { super(e); }
129 }
130
Gustav Sennton6ce92c92015-10-23 11:10:39 +0100131 /**
Gustav Sennton6ce92c92015-10-23 11:10:39 +0100132 * @hide
133 */
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000134 public static String getWebViewLibrary(ApplicationInfo ai) {
Gustav Sennton2ed6fee2015-03-03 15:12:34 +0000135 if (ai.metaData != null)
136 return ai.metaData.getString("com.android.webview.WebViewLibrary");
137 return null;
Ben Murdochdc00a842014-07-17 14:55:00 +0100138 }
139
Torne (Richard Coles)84392d72014-08-14 16:43:18 +0100140 public static PackageInfo getLoadedPackageInfo() {
141 return sPackageInfo;
142 }
143
Gustav Sennton85edb6c2015-04-15 11:54:20 +0100144 /**
145 * Load the native library for the given package name iff that package
Gustav Senntond97301822015-06-18 16:56:26 +0100146 * name is the same as the one providing the webview.
Gustav Sennton85edb6c2015-04-15 11:54:20 +0100147 */
Torne (Richard Coles)1a904122016-03-14 13:45:55 +0000148 public static int loadWebViewNativeLibraryFromPackage(String packageName,
149 ClassLoader clazzLoader) {
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000150 int ret = waitForProviderAndSetPackageInfo();
151 if (ret != LIBLOAD_SUCCESS) {
152 return ret;
Gustav Sennton6ce92c92015-10-23 11:10:39 +0100153 }
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000154 if (!sPackageInfo.packageName.equals(packageName))
155 return LIBLOAD_WRONG_PACKAGE_NAME;
Gustav Sennton6ce92c92015-10-23 11:10:39 +0100156
Torne (Richard Coles)1a904122016-03-14 13:45:55 +0000157 return loadNativeLibrary(clazzLoader);
Gustav Sennton85edb6c2015-04-15 11:54:20 +0100158 }
159
John Reck9f9d3452012-09-20 13:18:59 -0700160 static WebViewFactoryProvider getProvider() {
161 synchronized (sProviderLock) {
162 // For now the main purpose of this function (and the factory abstraction) is to keep
Torne (Richard Coles)d892afc2013-10-14 17:14:04 +0100163 // us honest and minimize usage of WebView internals when binding the proxy.
John Reck9f9d3452012-09-20 13:18:59 -0700164 if (sProviderInstance != null) return sProviderInstance;
Jonathan Dixond3101b12012-04-12 20:51:51 +0100165
Jeff Sharkey85844912014-11-13 16:20:38 -0800166 final int uid = android.os.Process.myUid();
167 if (uid == android.os.Process.ROOT_UID || uid == android.os.Process.SYSTEM_UID) {
168 throw new UnsupportedOperationException(
169 "For security reasons, WebView is not allowed in privileged processes");
170 }
171
Gustav Sennton5df5e222016-02-25 18:20:12 +0000172 StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
Torne (Richard Coles)38228822014-08-13 17:11:45 +0100173 Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "WebViewFactory.getProvider()");
Torne (Richard Coles)03ce9b32013-06-12 16:02:03 +0100174 try {
Gustav Senntona8366e72015-04-17 11:24:07 +0100175 Class<WebViewFactoryProvider> providerClass = getProviderClass();
Torne (Richard Coles)38228822014-08-13 17:11:45 +0100176
Torne (Richard Coles)38228822014-08-13 17:11:45 +0100177 Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "providerClass.newInstance()");
178 try {
Ignacio Solla1ea39b32014-11-10 14:08:37 +0000179 sProviderInstance = providerClass.getConstructor(WebViewDelegate.class)
180 .newInstance(new WebViewDelegate());
Torne (Richard Coles)38228822014-08-13 17:11:45 +0100181 if (DEBUG) Log.v(LOGTAG, "Loaded provider: " + sProviderInstance);
182 return sProviderInstance;
183 } catch (Exception e) {
184 Log.e(LOGTAG, "error instantiating provider", e);
185 throw new AndroidRuntimeException(e);
186 } finally {
187 Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW);
Torne (Richard Coles)38228822014-08-13 17:11:45 +0100188 }
Torne (Richard Coles)03ce9b32013-06-12 16:02:03 +0100189 } finally {
Torne (Richard Coles)38228822014-08-13 17:11:45 +0100190 Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW);
Gustav Sennton5df5e222016-02-25 18:20:12 +0000191 StrictMode.setThreadPolicy(oldPolicy);
Torne (Richard Coles)03ce9b32013-06-12 16:02:03 +0100192 }
Jonathan Dixond3101b12012-04-12 20:51:51 +0100193 }
Jonathan Dixond3101b12012-04-12 20:51:51 +0100194 }
195
Gustav Senntona8366e72015-04-17 11:24:07 +0100196 private static Class<WebViewFactoryProvider> getProviderClass() {
197 try {
Gustav Senntonfc424472016-01-06 17:11:09 +0000198 Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW,
199 "WebViewFactory.waitForProviderAndSetPackageInfo()");
200 try {
201 // First fetch the package info so we can log the webview package version.
202 int res = waitForProviderAndSetPackageInfo();
203 if (res != LIBLOAD_SUCCESS) {
204 throw new MissingWebViewPackageException(
205 "Failed to load WebView provider, error: "
206 + getWebViewPreparationErrorReason(res));
207 }
208 } finally {
209 Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW);
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000210 }
Gustav Senntona8366e72015-04-17 11:24:07 +0100211 Log.i(LOGTAG, "Loading " + sPackageInfo.packageName + " version " +
212 sPackageInfo.versionName + " (code " + sPackageInfo.versionCode + ")");
213
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000214 Application initialApplication = AppGlobals.getInitialApplication();
215 Context webViewContext = null;
Gustav Senntonb1e45cd2016-01-22 11:25:34 +0000216 Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "PackageManager.getApplicationInfo()");
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000217 try {
218 // Construct a package context to load the Java code into the current app.
219 // This is done as early as possible since by constructing a package context we
220 // register the WebView package as a dependency for the current application so that
221 // when the WebView package is updated this application will be killed.
Gustav Senntonb1e45cd2016-01-22 11:25:34 +0000222 ApplicationInfo applicationInfo =
223 initialApplication.getPackageManager().getApplicationInfo(
224 sPackageInfo.packageName, PackageManager.GET_SHARED_LIBRARY_FILES
225 | PackageManager.MATCH_DEBUG_TRIAGED_MISSING
226 // make sure that we fetch the current provider even if its not installed
227 // for the current user
228 | PackageManager.MATCH_UNINSTALLED_PACKAGES);
229 Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW,
230 "initialApplication.createApplicationContext");
231 try {
232 webViewContext = initialApplication.createApplicationContext(applicationInfo,
233 Context.CONTEXT_INCLUDE_CODE | Context.CONTEXT_IGNORE_SECURITY);
234 } finally {
235 Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW);
236 }
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000237 } catch (PackageManager.NameNotFoundException e) {
238 throw new MissingWebViewPackageException(e);
Gustav Senntonfc424472016-01-06 17:11:09 +0000239 } finally {
240 Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW);
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000241 }
242
Gustav Senntona8366e72015-04-17 11:24:07 +0100243 Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "WebViewFactory.getChromiumProviderClass()");
244 try {
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000245 initialApplication.getAssets().addAssetPathAsSharedLibrary(
246 webViewContext.getApplicationInfo().sourceDir);
247 ClassLoader clazzLoader = webViewContext.getClassLoader();
Torne (Richard Coles)1a904122016-03-14 13:45:55 +0000248
249 Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "WebViewFactory.loadNativeLibrary()");
250 loadNativeLibrary(clazzLoader);
251 Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW);
252
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000253 Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "Class.forName()");
254 try {
255 return (Class<WebViewFactoryProvider>) Class.forName(CHROMIUM_WEBVIEW_FACTORY,
256 true, clazzLoader);
257 } finally {
258 Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW);
259 }
Gustav Senntona8366e72015-04-17 11:24:07 +0100260 } catch (ClassNotFoundException e) {
261 Log.e(LOGTAG, "error loading provider", e);
262 throw new AndroidRuntimeException(e);
263 } finally {
264 Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW);
265 }
266 } catch (MissingWebViewPackageException e) {
267 // If the package doesn't exist, then try loading the null WebView instead.
268 // If that succeeds, then this is a device without WebView support; if it fails then
269 // swallow the failure, complain that the real WebView is missing and rethrow the
270 // original exception.
271 try {
272 return (Class<WebViewFactoryProvider>) Class.forName(NULL_WEBVIEW_FACTORY);
273 } catch (ClassNotFoundException e2) {
274 // Ignore.
275 }
276 Log.e(LOGTAG, "Chromium WebView package does not exist", e);
277 throw new AndroidRuntimeException(e);
278 }
279 }
280
Torne (Richard Coles)08cfaf62014-05-08 16:07:05 +0100281 /**
282 * Perform any WebView loading preparations that must happen in the zygote.
283 * Currently, this means allocating address space to load the real JNI library later.
284 */
285 public static void prepareWebViewInZygote() {
286 try {
287 System.loadLibrary("webviewchromium_loader");
Ben Murdoch5ced5022014-07-28 15:57:00 +0100288 long addressSpaceToReserve =
289 SystemProperties.getLong(CHROMIUM_WEBVIEW_VMSIZE_SIZE_PROPERTY,
290 CHROMIUM_WEBVIEW_DEFAULT_VMSIZE_BYTES);
291 sAddressSpaceReserved = nativeReserveAddressSpace(addressSpaceToReserve);
292
Torne (Richard Coles)08cfaf62014-05-08 16:07:05 +0100293 if (sAddressSpaceReserved) {
Ben Murdoch5ced5022014-07-28 15:57:00 +0100294 if (DEBUG) {
295 Log.v(LOGTAG, "address space reserved: " + addressSpaceToReserve + " bytes");
296 }
Torne (Richard Coles)08cfaf62014-05-08 16:07:05 +0100297 } else {
Ben Murdoch5ced5022014-07-28 15:57:00 +0100298 Log.e(LOGTAG, "reserving " + addressSpaceToReserve +
299 " bytes of address space failed");
Torne (Richard Coles)08cfaf62014-05-08 16:07:05 +0100300 }
Primiano Tucci810c0522014-07-25 18:03:16 +0100301 } catch (Throwable t) {
Torne (Richard Coles)08cfaf62014-05-08 16:07:05 +0100302 // Log and discard errors at this stage as we must not crash the zygote.
Primiano Tucci810c0522014-07-25 18:03:16 +0100303 Log.e(LOGTAG, "error preparing native loader", t);
Torne (Richard Coles)08cfaf62014-05-08 16:07:05 +0100304 }
305 }
306
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000307 private static int prepareWebViewInSystemServer(String[] nativeLibraryPaths) {
Torne (Richard Coles)08cfaf62014-05-08 16:07:05 +0100308 if (DEBUG) Log.v(LOGTAG, "creating relro files");
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000309 int numRelros = 0;
Ben Murdoch5ced5022014-07-28 15:57:00 +0100310
311 // We must always trigger createRelRo regardless of the value of nativeLibraryPaths. Any
312 // unexpected values will be handled there to ensure that we trigger notifying any process
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000313 // waiting on relro creation.
Ben Murdoch5ced5022014-07-28 15:57:00 +0100314 if (Build.SUPPORTED_32_BIT_ABIS.length > 0) {
315 if (DEBUG) Log.v(LOGTAG, "Create 32 bit relro");
316 createRelroFile(false /* is64Bit */, nativeLibraryPaths);
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000317 numRelros++;
Torne (Richard Coles)08cfaf62014-05-08 16:07:05 +0100318 }
Ben Murdoch5ced5022014-07-28 15:57:00 +0100319
320 if (Build.SUPPORTED_64_BIT_ABIS.length > 0) {
321 if (DEBUG) Log.v(LOGTAG, "Create 64 bit relro");
322 createRelroFile(true /* is64Bit */, nativeLibraryPaths);
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000323 numRelros++;
Torne (Richard Coles)08cfaf62014-05-08 16:07:05 +0100324 }
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000325 return numRelros;
Torne (Richard Coles)08cfaf62014-05-08 16:07:05 +0100326 }
327
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000328 /**
329 * @hide
330 */
331 public static int onWebViewProviderChanged(PackageInfo packageInfo) {
Ben Murdoch5ced5022014-07-28 15:57:00 +0100332 String[] nativeLibs = null;
333 try {
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000334 nativeLibs = WebViewFactory.getWebViewNativeLibraryPaths(packageInfo);
Torne (Richard Coles)27cb0d22014-08-08 18:24:12 +0100335 if (nativeLibs != null) {
336 long newVmSize = 0L;
Ben Murdoch5ced5022014-07-28 15:57:00 +0100337
Torne (Richard Coles)27cb0d22014-08-08 18:24:12 +0100338 for (String path : nativeLibs) {
Simon Baldwinb98082dc2015-05-15 12:56:50 +0100339 if (path == null || TextUtils.isEmpty(path)) continue;
Torne (Richard Coles)27cb0d22014-08-08 18:24:12 +0100340 if (DEBUG) Log.d(LOGTAG, "Checking file size of " + path);
Torne (Richard Coles)27cb0d22014-08-08 18:24:12 +0100341 File f = new File(path);
342 if (f.exists()) {
Simon Baldwinb98082dc2015-05-15 12:56:50 +0100343 newVmSize = Math.max(newVmSize, f.length());
344 continue;
345 }
Simon Baldwin519919b2015-06-11 17:09:49 +0100346 if (path.contains("!/")) {
347 String[] split = TextUtils.split(path, "!/");
Simon Baldwinb98082dc2015-05-15 12:56:50 +0100348 if (split.length == 2) {
Torne (Richard Coles)c5283922015-08-10 16:40:50 +0100349 try (ZipFile z = new ZipFile(split[0])) {
Simon Baldwinb98082dc2015-05-15 12:56:50 +0100350 ZipEntry e = z.getEntry(split[1]);
351 if (e != null && e.getMethod() == ZipEntry.STORED) {
352 newVmSize = Math.max(newVmSize, e.getSize());
353 continue;
354 }
355 }
356 catch (IOException e) {
357 Log.e(LOGTAG, "error reading APK file " + split[0] + ", ", e);
358 }
Torne (Richard Coles)27cb0d22014-08-08 18:24:12 +0100359 }
Ben Murdoch5ced5022014-07-28 15:57:00 +0100360 }
Simon Baldwinb98082dc2015-05-15 12:56:50 +0100361 Log.e(LOGTAG, "error sizing load for " + path);
Ben Murdoch5ced5022014-07-28 15:57:00 +0100362 }
Ben Murdoch5ced5022014-07-28 15:57:00 +0100363
Torne (Richard Coles)27cb0d22014-08-08 18:24:12 +0100364 if (DEBUG) {
365 Log.v(LOGTAG, "Based on library size, need " + newVmSize +
366 " bytes of address space.");
367 }
368 // The required memory can be larger than the file on disk (due to .bss), and an
369 // upgraded version of the library will likely be larger, so always attempt to
370 // reserve twice as much as we think to allow for the library to grow during this
371 // boot cycle.
372 newVmSize = Math.max(2 * newVmSize, CHROMIUM_WEBVIEW_DEFAULT_VMSIZE_BYTES);
373 Log.d(LOGTAG, "Setting new address space to " + newVmSize);
374 SystemProperties.set(CHROMIUM_WEBVIEW_VMSIZE_SIZE_PROPERTY,
375 Long.toString(newVmSize));
Ben Murdoch5ced5022014-07-28 15:57:00 +0100376 }
Torne (Richard Coles)27cb0d22014-08-08 18:24:12 +0100377 } catch (Throwable t) {
378 // Log and discard errors at this stage as we must not crash the system server.
379 Log.e(LOGTAG, "error preparing webview native library", t);
Ben Murdoch5ced5022014-07-28 15:57:00 +0100380 }
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000381 return prepareWebViewInSystemServer(nativeLibs);
Ben Murdoch5ced5022014-07-28 15:57:00 +0100382 }
383
Gustav Senntona8366e72015-04-17 11:24:07 +0100384 // throws MissingWebViewPackageException
Simon Baldwinb98082dc2015-05-15 12:56:50 +0100385 private static String getLoadFromApkPath(String apkPath,
386 String[] abiList,
387 String nativeLibFileName) {
388 // Search the APK for a native library conforming to a listed ABI.
Torne (Richard Coles)c5283922015-08-10 16:40:50 +0100389 try (ZipFile z = new ZipFile(apkPath)) {
Simon Baldwinb98082dc2015-05-15 12:56:50 +0100390 for (String abi : abiList) {
391 final String entry = "lib/" + abi + "/" + nativeLibFileName;
392 ZipEntry e = z.getEntry(entry);
393 if (e != null && e.getMethod() == ZipEntry.STORED) {
394 // Return a path formatted for dlopen() load from APK.
Simon Baldwin519919b2015-06-11 17:09:49 +0100395 return apkPath + "!/" + entry;
Simon Baldwinb98082dc2015-05-15 12:56:50 +0100396 }
397 }
398 } catch (IOException e) {
399 throw new MissingWebViewPackageException(e);
400 }
401 return "";
402 }
403
404 // throws MissingWebViewPackageException
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000405 private static String[] getWebViewNativeLibraryPaths(PackageInfo packageInfo) {
406 ApplicationInfo ai = packageInfo.applicationInfo;
Gustav Sennton2ed6fee2015-03-03 15:12:34 +0000407 final String NATIVE_LIB_FILE_NAME = getWebViewLibrary(ai);
Primiano Tucci1b7977b2014-07-25 19:19:32 +0100408
409 String path32;
410 String path64;
411 boolean primaryArchIs64bit = VMRuntime.is64BitAbi(ai.primaryCpuAbi);
412 if (!TextUtils.isEmpty(ai.secondaryCpuAbi)) {
413 // Multi-arch case.
414 if (primaryArchIs64bit) {
415 // Primary arch: 64-bit, secondary: 32-bit.
416 path64 = ai.nativeLibraryDir;
417 path32 = ai.secondaryNativeLibraryDir;
418 } else {
419 // Primary arch: 32-bit, secondary: 64-bit.
420 path64 = ai.secondaryNativeLibraryDir;
421 path32 = ai.nativeLibraryDir;
422 }
423 } else if (primaryArchIs64bit) {
424 // Single-arch 64-bit.
425 path64 = ai.nativeLibraryDir;
426 path32 = "";
427 } else {
428 // Single-arch 32-bit.
429 path32 = ai.nativeLibraryDir;
430 path64 = "";
431 }
Simon Baldwinb98082dc2015-05-15 12:56:50 +0100432
433 // Form the full paths to the extracted native libraries.
434 // If libraries were not extracted, try load from APK paths instead.
435 if (!TextUtils.isEmpty(path32)) {
436 path32 += "/" + NATIVE_LIB_FILE_NAME;
437 File f = new File(path32);
438 if (!f.exists()) {
439 path32 = getLoadFromApkPath(ai.sourceDir,
440 Build.SUPPORTED_32_BIT_ABIS,
441 NATIVE_LIB_FILE_NAME);
442 }
443 }
444 if (!TextUtils.isEmpty(path64)) {
445 path64 += "/" + NATIVE_LIB_FILE_NAME;
446 File f = new File(path64);
447 if (!f.exists()) {
448 path64 = getLoadFromApkPath(ai.sourceDir,
449 Build.SUPPORTED_64_BIT_ABIS,
450 NATIVE_LIB_FILE_NAME);
451 }
452 }
453
454 if (DEBUG) Log.v(LOGTAG, "Native 32-bit lib: " + path32 + ", 64-bit lib: " + path64);
Primiano Tucci1b7977b2014-07-25 19:19:32 +0100455 return new String[] { path32, path64 };
456 }
457
Ben Murdoch5ced5022014-07-28 15:57:00 +0100458 private static void createRelroFile(final boolean is64Bit, String[] nativeLibraryPaths) {
Primiano Tucci1b7977b2014-07-25 19:19:32 +0100459 final String abi =
460 is64Bit ? Build.SUPPORTED_64_BIT_ABIS[0] : Build.SUPPORTED_32_BIT_ABIS[0];
Primiano Tucci810c0522014-07-25 18:03:16 +0100461
462 // crashHandler is invoked by the ActivityManagerService when the isolated process crashes.
463 Runnable crashHandler = new Runnable() {
464 @Override
465 public void run() {
466 try {
Primiano Tucci1b7977b2014-07-25 19:19:32 +0100467 Log.e(LOGTAG, "relro file creator for " + abi + " crashed. Proceeding without");
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000468 getUpdateService().notifyRelroCreationCompleted();
Primiano Tucci810c0522014-07-25 18:03:16 +0100469 } catch (RemoteException e) {
470 Log.e(LOGTAG, "Cannot reach WebViewUpdateService. " + e.getMessage());
471 }
472 }
473 };
474
Torne (Richard Coles)08cfaf62014-05-08 16:07:05 +0100475 try {
Ben Murdoch5ced5022014-07-28 15:57:00 +0100476 if (nativeLibraryPaths == null
477 || nativeLibraryPaths[0] == null || nativeLibraryPaths[1] == null) {
478 throw new IllegalArgumentException(
479 "Native library paths to the WebView RelRo process must not be null!");
480 }
Primiano Tucci161536b2014-07-28 18:51:45 +0100481 int pid = LocalServices.getService(ActivityManagerInternal.class).startIsolatedProcess(
Ben Murdoch5ced5022014-07-28 15:57:00 +0100482 RelroFileCreator.class.getName(), nativeLibraryPaths, "WebViewLoader-" + abi, abi,
Primiano Tucci810c0522014-07-25 18:03:16 +0100483 Process.SHARED_RELRO_UID, crashHandler);
Primiano Tuccie76e81a2014-07-29 16:38:33 +0100484 if (pid <= 0) throw new Exception("Failed to start the relro file creator process");
Primiano Tucci810c0522014-07-25 18:03:16 +0100485 } catch (Throwable t) {
Torne (Richard Coles)08cfaf62014-05-08 16:07:05 +0100486 // Log and discard errors as we must not crash the system server.
Primiano Tucci810c0522014-07-25 18:03:16 +0100487 Log.e(LOGTAG, "error starting relro file creator for abi " + abi, t);
488 crashHandler.run();
Torne (Richard Coles)08cfaf62014-05-08 16:07:05 +0100489 }
490 }
491
492 private static class RelroFileCreator {
493 // Called in an unprivileged child process to create the relro file.
494 public static void main(String[] args) {
Primiano Tucci161536b2014-07-28 18:51:45 +0100495 boolean result = false;
496 boolean is64Bit = VMRuntime.getRuntime().is64Bit();
Primiano Tucci1b7977b2014-07-25 19:19:32 +0100497 try{
498 if (args.length != 2 || args[0] == null || args[1] == null) {
499 Log.e(LOGTAG, "Invalid RelroFileCreator args: " + Arrays.toString(args));
500 return;
501 }
Primiano Tucci1b7977b2014-07-25 19:19:32 +0100502 Log.v(LOGTAG, "RelroFileCreator (64bit = " + is64Bit + "), " +
503 " 32-bit lib: " + args[0] + ", 64-bit lib: " + args[1]);
504 if (!sAddressSpaceReserved) {
505 Log.e(LOGTAG, "can't create relro file; address space not reserved");
506 return;
507 }
Primiano Tucci161536b2014-07-28 18:51:45 +0100508 result = nativeCreateRelroFile(args[0] /* path32 */,
509 args[1] /* path64 */,
510 CHROMIUM_WEBVIEW_NATIVE_RELRO_32,
511 CHROMIUM_WEBVIEW_NATIVE_RELRO_64);
Primiano Tuccie76e81a2014-07-29 16:38:33 +0100512 if (result && DEBUG) Log.v(LOGTAG, "created relro file");
Primiano Tucci161536b2014-07-28 18:51:45 +0100513 } finally {
514 // We must do our best to always notify the update service, even if something fails.
Primiano Tucci1b7977b2014-07-25 19:19:32 +0100515 try {
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000516 getUpdateService().notifyRelroCreationCompleted();
Primiano Tucci1b7977b2014-07-25 19:19:32 +0100517 } catch (RemoteException e) {
518 Log.e(LOGTAG, "error notifying update service", e);
519 }
Primiano Tucci161536b2014-07-28 18:51:45 +0100520
521 if (!result) Log.e(LOGTAG, "failed to create relro file");
522
Primiano Tucci1b7977b2014-07-25 19:19:32 +0100523 // Must explicitly exit or else this process will just sit around after we return.
524 System.exit(0);
525 }
Torne (Richard Coles)08cfaf62014-05-08 16:07:05 +0100526 }
527 }
528
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000529 private static int waitForProviderAndSetPackageInfo() {
530 WebViewProviderResponse response = null;
531 try {
532 response =
533 getUpdateService().waitForAndGetProvider();
534 if (response.status == WebViewFactory.LIBLOAD_SUCCESS)
535 sPackageInfo = response.packageInfo;
536 } catch (RemoteException e) {
537 Log.e(LOGTAG, "error waiting for relro creation", e);
538 return LIBLOAD_FAILED_WAITING_FOR_WEBVIEW_REASON_UNKNOWN;
539 }
540 return response.status;
541 }
542
543 // Assumes that we have waited for relro creation and set sPackageInfo
Torne (Richard Coles)1a904122016-03-14 13:45:55 +0000544 private static int loadNativeLibrary(ClassLoader clazzLoader) {
Torne (Richard Coles)08cfaf62014-05-08 16:07:05 +0100545 if (!sAddressSpaceReserved) {
546 Log.e(LOGTAG, "can't load with relro file; address space not reserved");
Gustav Sennton85edb6c2015-04-15 11:54:20 +0100547 return LIBLOAD_ADDRESS_SPACE_NOT_RESERVED;
Torne (Richard Coles)08cfaf62014-05-08 16:07:05 +0100548 }
549
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000550 String[] args = getWebViewNativeLibraryPaths(sPackageInfo);
551 int result = nativeLoadWithRelroFile(args[0] /* path32 */,
Torne (Richard Coles)1a904122016-03-14 13:45:55 +0000552 args[1] /* path64 */,
553 CHROMIUM_WEBVIEW_NATIVE_RELRO_32,
554 CHROMIUM_WEBVIEW_NATIVE_RELRO_64,
555 clazzLoader);
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000556 if (result != LIBLOAD_SUCCESS) {
557 Log.w(LOGTAG, "failed to load with relro file, proceeding without");
558 } else if (DEBUG) {
559 Log.v(LOGTAG, "loaded with relro file");
Torne (Richard Coles)08cfaf62014-05-08 16:07:05 +0100560 }
Gustav Sennton6258dcd2015-10-30 19:25:37 +0000561 return result;
Torne (Richard Coles)08cfaf62014-05-08 16:07:05 +0100562 }
563
Gustav Senntonc83e3fa2016-02-18 12:19:13 +0000564 /**
565 * Returns whether the entire package from an ACTION_PACKAGE_CHANGED intent was changed (rather
566 * than just one of its components).
567 * @hide
568 */
569 public static boolean entirePackageChanged(Intent intent) {
570 String[] componentList =
571 intent.getStringArrayExtra(Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST);
572 return Arrays.asList(componentList).contains(
573 intent.getDataString().substring("package:".length()));
574 }
575
Torne (Richard Coles)08cfaf62014-05-08 16:07:05 +0100576 private static IWebViewUpdateService getUpdateService() {
577 return IWebViewUpdateService.Stub.asInterface(ServiceManager.getService("webviewupdate"));
578 }
579
Ben Murdoch5ced5022014-07-28 15:57:00 +0100580 private static native boolean nativeReserveAddressSpace(long addressSpaceToReserve);
Torne (Richard Coles)08cfaf62014-05-08 16:07:05 +0100581 private static native boolean nativeCreateRelroFile(String lib32, String lib64,
582 String relro32, String relro64);
Gustav Sennton85edb6c2015-04-15 11:54:20 +0100583 private static native int nativeLoadWithRelroFile(String lib32, String lib64,
Torne (Richard Coles)1a904122016-03-14 13:45:55 +0000584 String relro32, String relro64,
585 ClassLoader clazzLoader);
Jonathan Dixond3101b12012-04-12 20:51:51 +0100586}