blob: 3340c73c32db316e7f2e77155aae93b8a1c12516 [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;
Primiano Tucci1b7977b2014-07-25 19:19:32 +010024import android.content.pm.ApplicationInfo;
Torne (Richard Coles)0606cd52014-08-05 16:12:09 +010025import android.content.pm.PackageInfo;
Torne (Richard Coles)6c778ce2014-07-17 14:14:48 -070026import android.content.pm.PackageManager;
Torne (Richard Coles)08cfaf62014-05-08 16:07:05 +010027import android.os.Build;
28import android.os.Process;
29import android.os.RemoteException;
30import android.os.ServiceManager;
Ben Murdoche09e9762012-07-19 14:48:13 +010031import android.os.StrictMode;
Ben Murdoch5ced5022014-07-28 15:57:00 +010032import android.os.SystemProperties;
Torne (Richard Coles)38228822014-08-13 17:11:45 +010033import android.os.Trace;
Primiano Tucci1b7977b2014-07-25 19:19:32 +010034import android.text.TextUtils;
Torne (Richard Coles)03ce9b32013-06-12 16:02:03 +010035import android.util.AndroidRuntimeException;
Jonathan Dixond3101b12012-04-12 20:51:51 +010036import android.util.Log;
Jeff Sharkey85844912014-11-13 16:20:38 -080037
Primiano Tucci810c0522014-07-25 18:03:16 +010038import com.android.server.LocalServices;
Jeff Sharkey85844912014-11-13 16:20:38 -080039
Torne (Richard Coles)08cfaf62014-05-08 16:07:05 +010040import dalvik.system.VMRuntime;
41
42import java.io.File;
Primiano Tucci1b7977b2014-07-25 19:19:32 +010043import java.util.Arrays;
Torne (Richard Coles)08cfaf62014-05-08 16:07:05 +010044
Jonathan Dixond3101b12012-04-12 20:51:51 +010045/**
46 * Top level factory, used creating all the main WebView implementation classes.
Jared Dukeb0e35842013-03-19 16:25:39 -070047 *
48 * @hide
Jonathan Dixond3101b12012-04-12 20:51:51 +010049 */
Ignacio Solla451e3382014-11-10 10:35:54 +000050@SystemApi
Jared Dukeb0e35842013-03-19 16:25:39 -070051public final class WebViewFactory {
Jonathan Dixona7eaa8e2013-07-25 19:52:47 -070052
Ben Murdoche09e9762012-07-19 14:48:13 +010053 private static final String CHROMIUM_WEBVIEW_FACTORY =
Torne (Richard Coles)a9bbd942012-10-24 11:59:22 +010054 "com.android.webview.chromium.WebViewChromiumFactoryProvider";
Jonathan Dixond3101b12012-04-12 20:51:51 +010055
Ben Murdoch0e04bcf2014-05-16 13:41:12 +010056 private static final String NULL_WEBVIEW_FACTORY =
57 "com.android.webview.nullwebview.NullWebViewFactoryProvider";
58
Torne (Richard Coles)08cfaf62014-05-08 16:07:05 +010059 private static final String CHROMIUM_WEBVIEW_NATIVE_RELRO_32 =
60 "/data/misc/shared_relro/libwebviewchromium32.relro";
61 private static final String CHROMIUM_WEBVIEW_NATIVE_RELRO_64 =
62 "/data/misc/shared_relro/libwebviewchromium64.relro";
63
Ben Murdoch5ced5022014-07-28 15:57:00 +010064 public static final String CHROMIUM_WEBVIEW_VMSIZE_SIZE_PROPERTY =
65 "persist.sys.webview.vmsize";
66 private static final long CHROMIUM_WEBVIEW_DEFAULT_VMSIZE_BYTES = 100 * 1024 * 1024;
Primiano Tucci1b7977b2014-07-25 19:19:32 +010067
Jonathan Dixond3101b12012-04-12 20:51:51 +010068 private static final String LOGTAG = "WebViewFactory";
69
70 private static final boolean DEBUG = false;
71
72 // Cache the factory both for efficiency, and ensure any one process gets all webviews from the
73 // same provider.
74 private static WebViewFactoryProvider sProviderInstance;
John Reck9f9d3452012-09-20 13:18:59 -070075 private static final Object sProviderLock = new Object();
Torne (Richard Coles)08cfaf62014-05-08 16:07:05 +010076 private static boolean sAddressSpaceReserved = false;
Torne (Richard Coles)84392d72014-08-14 16:43:18 +010077 private static PackageInfo sPackageInfo;
Jonathan Dixond3101b12012-04-12 20:51:51 +010078
Gustav Senntona8366e72015-04-17 11:24:07 +010079 private static class MissingWebViewPackageException extends AndroidRuntimeException {
80 public MissingWebViewPackageException(String message) { super(message); }
81 public MissingWebViewPackageException(Exception e) { super(e); }
82 }
83
Gustav Sennton2ed6fee2015-03-03 15:12:34 +000084 /** @hide */
85 public static String[] getWebViewPackageNames() {
86 return AppGlobals.getInitialApplication().getResources().getStringArray(
87 com.android.internal.R.array.config_webViewPackageNames);
88 }
89
90 // TODO (gsennton) remove when committing webview xts test change
Ben Murdochdc00a842014-07-17 14:55:00 +010091 public static String getWebViewPackageName() {
Gustav Sennton2ed6fee2015-03-03 15:12:34 +000092 String[] webViewPackageNames = getWebViewPackageNames();
93 return webViewPackageNames[webViewPackageNames.length-1];
94 }
95
96 /**
97 * Return the package info of the first package in the webview priority list that contains
98 * webview.
99 *
100 * @hide
101 */
102 public static PackageInfo findPreferredWebViewPackage() {
103 PackageManager pm = AppGlobals.getInitialApplication().getPackageManager();
104
105 for (String packageName : getWebViewPackageNames()) {
106 try {
107 PackageInfo packageInfo = pm.getPackageInfo(packageName,
108 PackageManager.GET_META_DATA);
109 ApplicationInfo applicationInfo = packageInfo.applicationInfo;
110
111 // If the correct flag is set the package contains webview.
112 if (getWebViewLibrary(applicationInfo) != null) {
113 return packageInfo;
114 }
115 } catch (PackageManager.NameNotFoundException e) {
116 }
117 }
Gustav Senntona8366e72015-04-17 11:24:07 +0100118 throw new MissingWebViewPackageException("Could not find a loadable WebView package");
Gustav Sennton2ed6fee2015-03-03 15:12:34 +0000119 }
120
Gustav Senntona8366e72015-04-17 11:24:07 +0100121 // throws MissingWebViewPackageException
Gustav Sennton2ed6fee2015-03-03 15:12:34 +0000122 private static ApplicationInfo getWebViewApplicationInfo() {
123 if (sPackageInfo == null)
124 return findPreferredWebViewPackage().applicationInfo;
125 else
126 return sPackageInfo.applicationInfo;
127 }
128
129 private static String getWebViewLibrary(ApplicationInfo ai) {
130 if (ai.metaData != null)
131 return ai.metaData.getString("com.android.webview.WebViewLibrary");
132 return null;
Ben Murdochdc00a842014-07-17 14:55:00 +0100133 }
134
Torne (Richard Coles)84392d72014-08-14 16:43:18 +0100135 public static PackageInfo getLoadedPackageInfo() {
136 return sPackageInfo;
137 }
138
John Reck9f9d3452012-09-20 13:18:59 -0700139 static WebViewFactoryProvider getProvider() {
140 synchronized (sProviderLock) {
141 // For now the main purpose of this function (and the factory abstraction) is to keep
Torne (Richard Coles)d892afc2013-10-14 17:14:04 +0100142 // us honest and minimize usage of WebView internals when binding the proxy.
John Reck9f9d3452012-09-20 13:18:59 -0700143 if (sProviderInstance != null) return sProviderInstance;
Jonathan Dixond3101b12012-04-12 20:51:51 +0100144
Jeff Sharkey85844912014-11-13 16:20:38 -0800145 final int uid = android.os.Process.myUid();
146 if (uid == android.os.Process.ROOT_UID || uid == android.os.Process.SYSTEM_UID) {
147 throw new UnsupportedOperationException(
148 "For security reasons, WebView is not allowed in privileged processes");
149 }
150
Torne (Richard Coles)38228822014-08-13 17:11:45 +0100151 Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "WebViewFactory.getProvider()");
Torne (Richard Coles)03ce9b32013-06-12 16:02:03 +0100152 try {
Gustav Senntona8366e72015-04-17 11:24:07 +0100153 Class<WebViewFactoryProvider> providerClass = getProviderClass();
Torne (Richard Coles)38228822014-08-13 17:11:45 +0100154
155 StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
156 Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "providerClass.newInstance()");
157 try {
Ignacio Solla1ea39b32014-11-10 14:08:37 +0000158 sProviderInstance = providerClass.getConstructor(WebViewDelegate.class)
159 .newInstance(new WebViewDelegate());
Torne (Richard Coles)38228822014-08-13 17:11:45 +0100160 if (DEBUG) Log.v(LOGTAG, "Loaded provider: " + sProviderInstance);
161 return sProviderInstance;
162 } catch (Exception e) {
163 Log.e(LOGTAG, "error instantiating provider", e);
164 throw new AndroidRuntimeException(e);
165 } finally {
166 Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW);
167 StrictMode.setThreadPolicy(oldPolicy);
168 }
Torne (Richard Coles)03ce9b32013-06-12 16:02:03 +0100169 } finally {
Torne (Richard Coles)38228822014-08-13 17:11:45 +0100170 Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW);
Torne (Richard Coles)03ce9b32013-06-12 16:02:03 +0100171 }
Jonathan Dixond3101b12012-04-12 20:51:51 +0100172 }
Jonathan Dixond3101b12012-04-12 20:51:51 +0100173 }
174
Gustav Senntona8366e72015-04-17 11:24:07 +0100175 private static Class<WebViewFactoryProvider> getProviderClass() {
176 try {
177 // First fetch the package info so we can log the webview package version.
178 sPackageInfo = findPreferredWebViewPackage();
179 Log.i(LOGTAG, "Loading " + sPackageInfo.packageName + " version " +
180 sPackageInfo.versionName + " (code " + sPackageInfo.versionCode + ")");
181
182 Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "WebViewFactory.loadNativeLibrary()");
183 loadNativeLibrary();
184 Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW);
185
186 Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "WebViewFactory.getChromiumProviderClass()");
187 try {
188 return getChromiumProviderClass();
189 } catch (ClassNotFoundException e) {
190 Log.e(LOGTAG, "error loading provider", e);
191 throw new AndroidRuntimeException(e);
192 } finally {
193 Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW);
194 }
195 } catch (MissingWebViewPackageException e) {
196 // If the package doesn't exist, then try loading the null WebView instead.
197 // If that succeeds, then this is a device without WebView support; if it fails then
198 // swallow the failure, complain that the real WebView is missing and rethrow the
199 // original exception.
200 try {
201 return (Class<WebViewFactoryProvider>) Class.forName(NULL_WEBVIEW_FACTORY);
202 } catch (ClassNotFoundException e2) {
203 // Ignore.
204 }
205 Log.e(LOGTAG, "Chromium WebView package does not exist", e);
206 throw new AndroidRuntimeException(e);
207 }
208 }
209
210 // throws MissingWebViewPackageException
211 private static Class<WebViewFactoryProvider> getChromiumProviderClass()
212 throws ClassNotFoundException {
Marcin Kosiba63d3d8a2014-07-22 19:22:48 +0100213 Application initialApplication = AppGlobals.getInitialApplication();
Ben Murdoch0e04bcf2014-05-16 13:41:12 +0100214 try {
Torne (Richard Coles)0606cd52014-08-05 16:12:09 +0100215 // Construct a package context to load the Java code into the current app.
Gustav Sennton2ed6fee2015-03-03 15:12:34 +0000216 Context webViewContext = initialApplication.createPackageContext(
217 sPackageInfo.packageName,
218 Context.CONTEXT_INCLUDE_CODE | Context.CONTEXT_IGNORE_SECURITY);
Marcin Kosiba63d3d8a2014-07-22 19:22:48 +0100219 initialApplication.getAssets().addAssetPath(
220 webViewContext.getApplicationInfo().sourceDir);
Torne (Richard Coles)6c778ce2014-07-17 14:14:48 -0700221 ClassLoader clazzLoader = webViewContext.getClassLoader();
Torne (Richard Coles)38228822014-08-13 17:11:45 +0100222 Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "Class.forName()");
223 try {
224 return (Class<WebViewFactoryProvider>) Class.forName(CHROMIUM_WEBVIEW_FACTORY, true,
225 clazzLoader);
226 } finally {
227 Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW);
228 }
Torne (Richard Coles)6c778ce2014-07-17 14:14:48 -0700229 } catch (PackageManager.NameNotFoundException e) {
Gustav Senntona8366e72015-04-17 11:24:07 +0100230 throw new MissingWebViewPackageException(e);
Ben Murdoch0e04bcf2014-05-16 13:41:12 +0100231 }
Jonathan Dixond3101b12012-04-12 20:51:51 +0100232 }
Torne (Richard Coles)08cfaf62014-05-08 16:07:05 +0100233
234 /**
235 * Perform any WebView loading preparations that must happen in the zygote.
236 * Currently, this means allocating address space to load the real JNI library later.
237 */
238 public static void prepareWebViewInZygote() {
239 try {
240 System.loadLibrary("webviewchromium_loader");
Ben Murdoch5ced5022014-07-28 15:57:00 +0100241 long addressSpaceToReserve =
242 SystemProperties.getLong(CHROMIUM_WEBVIEW_VMSIZE_SIZE_PROPERTY,
243 CHROMIUM_WEBVIEW_DEFAULT_VMSIZE_BYTES);
244 sAddressSpaceReserved = nativeReserveAddressSpace(addressSpaceToReserve);
245
Torne (Richard Coles)08cfaf62014-05-08 16:07:05 +0100246 if (sAddressSpaceReserved) {
Ben Murdoch5ced5022014-07-28 15:57:00 +0100247 if (DEBUG) {
248 Log.v(LOGTAG, "address space reserved: " + addressSpaceToReserve + " bytes");
249 }
Torne (Richard Coles)08cfaf62014-05-08 16:07:05 +0100250 } else {
Ben Murdoch5ced5022014-07-28 15:57:00 +0100251 Log.e(LOGTAG, "reserving " + addressSpaceToReserve +
252 " bytes of address space failed");
Torne (Richard Coles)08cfaf62014-05-08 16:07:05 +0100253 }
Primiano Tucci810c0522014-07-25 18:03:16 +0100254 } catch (Throwable t) {
Torne (Richard Coles)08cfaf62014-05-08 16:07:05 +0100255 // Log and discard errors at this stage as we must not crash the zygote.
Primiano Tucci810c0522014-07-25 18:03:16 +0100256 Log.e(LOGTAG, "error preparing native loader", t);
Torne (Richard Coles)08cfaf62014-05-08 16:07:05 +0100257 }
258 }
259
260 /**
261 * Perform any WebView loading preparations that must happen at boot from the system server,
Ben Murdoch5ced5022014-07-28 15:57:00 +0100262 * after the package manager has started or after an update to the webview is installed.
Torne (Richard Coles)08cfaf62014-05-08 16:07:05 +0100263 * This must be called in the system server.
264 * Currently, this means spawning the child processes which will create the relro files.
265 */
266 public static void prepareWebViewInSystemServer() {
Ben Murdoch5ced5022014-07-28 15:57:00 +0100267 String[] nativePaths = null;
268 try {
269 nativePaths = getWebViewNativeLibraryPaths();
Torne (Richard Coles)27cb0d22014-08-08 18:24:12 +0100270 } catch (Throwable t) {
271 // Log and discard errors at this stage as we must not crash the system server.
272 Log.e(LOGTAG, "error preparing webview native library", t);
Ben Murdoch5ced5022014-07-28 15:57:00 +0100273 }
274 prepareWebViewInSystemServer(nativePaths);
275 }
276
277 private static void prepareWebViewInSystemServer(String[] nativeLibraryPaths) {
Torne (Richard Coles)08cfaf62014-05-08 16:07:05 +0100278 if (DEBUG) Log.v(LOGTAG, "creating relro files");
Ben Murdoch5ced5022014-07-28 15:57:00 +0100279
280 // We must always trigger createRelRo regardless of the value of nativeLibraryPaths. Any
281 // unexpected values will be handled there to ensure that we trigger notifying any process
282 // waiting on relreo creation.
283 if (Build.SUPPORTED_32_BIT_ABIS.length > 0) {
284 if (DEBUG) Log.v(LOGTAG, "Create 32 bit relro");
285 createRelroFile(false /* is64Bit */, nativeLibraryPaths);
Torne (Richard Coles)08cfaf62014-05-08 16:07:05 +0100286 }
Ben Murdoch5ced5022014-07-28 15:57:00 +0100287
288 if (Build.SUPPORTED_64_BIT_ABIS.length > 0) {
289 if (DEBUG) Log.v(LOGTAG, "Create 64 bit relro");
290 createRelroFile(true /* is64Bit */, nativeLibraryPaths);
Torne (Richard Coles)08cfaf62014-05-08 16:07:05 +0100291 }
292 }
293
Ben Murdoch5ced5022014-07-28 15:57:00 +0100294 public static void onWebViewUpdateInstalled() {
295 String[] nativeLibs = null;
296 try {
297 nativeLibs = WebViewFactory.getWebViewNativeLibraryPaths();
Torne (Richard Coles)27cb0d22014-08-08 18:24:12 +0100298 if (nativeLibs != null) {
299 long newVmSize = 0L;
Ben Murdoch5ced5022014-07-28 15:57:00 +0100300
Torne (Richard Coles)27cb0d22014-08-08 18:24:12 +0100301 for (String path : nativeLibs) {
302 if (DEBUG) Log.d(LOGTAG, "Checking file size of " + path);
303 if (path == null) continue;
304 File f = new File(path);
305 if (f.exists()) {
306 long length = f.length();
307 if (length > newVmSize) {
308 newVmSize = length;
309 }
Ben Murdoch5ced5022014-07-28 15:57:00 +0100310 }
311 }
Ben Murdoch5ced5022014-07-28 15:57:00 +0100312
Torne (Richard Coles)27cb0d22014-08-08 18:24:12 +0100313 if (DEBUG) {
314 Log.v(LOGTAG, "Based on library size, need " + newVmSize +
315 " bytes of address space.");
316 }
317 // The required memory can be larger than the file on disk (due to .bss), and an
318 // upgraded version of the library will likely be larger, so always attempt to
319 // reserve twice as much as we think to allow for the library to grow during this
320 // boot cycle.
321 newVmSize = Math.max(2 * newVmSize, CHROMIUM_WEBVIEW_DEFAULT_VMSIZE_BYTES);
322 Log.d(LOGTAG, "Setting new address space to " + newVmSize);
323 SystemProperties.set(CHROMIUM_WEBVIEW_VMSIZE_SIZE_PROPERTY,
324 Long.toString(newVmSize));
Ben Murdoch5ced5022014-07-28 15:57:00 +0100325 }
Torne (Richard Coles)27cb0d22014-08-08 18:24:12 +0100326 } catch (Throwable t) {
327 // Log and discard errors at this stage as we must not crash the system server.
328 Log.e(LOGTAG, "error preparing webview native library", t);
Ben Murdoch5ced5022014-07-28 15:57:00 +0100329 }
330 prepareWebViewInSystemServer(nativeLibs);
331 }
332
Gustav Senntona8366e72015-04-17 11:24:07 +0100333 // throws MissingWebViewPackageException
334 private static String[] getWebViewNativeLibraryPaths() {
Gustav Sennton2ed6fee2015-03-03 15:12:34 +0000335 ApplicationInfo ai = getWebViewApplicationInfo();
336 final String NATIVE_LIB_FILE_NAME = getWebViewLibrary(ai);
Primiano Tucci1b7977b2014-07-25 19:19:32 +0100337
338 String path32;
339 String path64;
340 boolean primaryArchIs64bit = VMRuntime.is64BitAbi(ai.primaryCpuAbi);
341 if (!TextUtils.isEmpty(ai.secondaryCpuAbi)) {
342 // Multi-arch case.
343 if (primaryArchIs64bit) {
344 // Primary arch: 64-bit, secondary: 32-bit.
345 path64 = ai.nativeLibraryDir;
346 path32 = ai.secondaryNativeLibraryDir;
347 } else {
348 // Primary arch: 32-bit, secondary: 64-bit.
349 path64 = ai.secondaryNativeLibraryDir;
350 path32 = ai.nativeLibraryDir;
351 }
352 } else if (primaryArchIs64bit) {
353 // Single-arch 64-bit.
354 path64 = ai.nativeLibraryDir;
355 path32 = "";
356 } else {
357 // Single-arch 32-bit.
358 path32 = ai.nativeLibraryDir;
359 path64 = "";
360 }
361 if (!TextUtils.isEmpty(path32)) path32 += "/" + NATIVE_LIB_FILE_NAME;
362 if (!TextUtils.isEmpty(path64)) path64 += "/" + NATIVE_LIB_FILE_NAME;
363 return new String[] { path32, path64 };
364 }
365
Ben Murdoch5ced5022014-07-28 15:57:00 +0100366 private static void createRelroFile(final boolean is64Bit, String[] nativeLibraryPaths) {
Primiano Tucci1b7977b2014-07-25 19:19:32 +0100367 final String abi =
368 is64Bit ? Build.SUPPORTED_64_BIT_ABIS[0] : Build.SUPPORTED_32_BIT_ABIS[0];
Primiano Tucci810c0522014-07-25 18:03:16 +0100369
370 // crashHandler is invoked by the ActivityManagerService when the isolated process crashes.
371 Runnable crashHandler = new Runnable() {
372 @Override
373 public void run() {
374 try {
Primiano Tucci1b7977b2014-07-25 19:19:32 +0100375 Log.e(LOGTAG, "relro file creator for " + abi + " crashed. Proceeding without");
Primiano Tucci810c0522014-07-25 18:03:16 +0100376 getUpdateService().notifyRelroCreationCompleted(is64Bit, false);
377 } catch (RemoteException e) {
378 Log.e(LOGTAG, "Cannot reach WebViewUpdateService. " + e.getMessage());
379 }
380 }
381 };
382
Torne (Richard Coles)08cfaf62014-05-08 16:07:05 +0100383 try {
Ben Murdoch5ced5022014-07-28 15:57:00 +0100384 if (nativeLibraryPaths == null
385 || nativeLibraryPaths[0] == null || nativeLibraryPaths[1] == null) {
386 throw new IllegalArgumentException(
387 "Native library paths to the WebView RelRo process must not be null!");
388 }
Primiano Tucci161536b2014-07-28 18:51:45 +0100389 int pid = LocalServices.getService(ActivityManagerInternal.class).startIsolatedProcess(
Ben Murdoch5ced5022014-07-28 15:57:00 +0100390 RelroFileCreator.class.getName(), nativeLibraryPaths, "WebViewLoader-" + abi, abi,
Primiano Tucci810c0522014-07-25 18:03:16 +0100391 Process.SHARED_RELRO_UID, crashHandler);
Primiano Tuccie76e81a2014-07-29 16:38:33 +0100392 if (pid <= 0) throw new Exception("Failed to start the relro file creator process");
Primiano Tucci810c0522014-07-25 18:03:16 +0100393 } catch (Throwable t) {
Torne (Richard Coles)08cfaf62014-05-08 16:07:05 +0100394 // Log and discard errors as we must not crash the system server.
Primiano Tucci810c0522014-07-25 18:03:16 +0100395 Log.e(LOGTAG, "error starting relro file creator for abi " + abi, t);
396 crashHandler.run();
Torne (Richard Coles)08cfaf62014-05-08 16:07:05 +0100397 }
398 }
399
400 private static class RelroFileCreator {
401 // Called in an unprivileged child process to create the relro file.
402 public static void main(String[] args) {
Primiano Tucci161536b2014-07-28 18:51:45 +0100403 boolean result = false;
404 boolean is64Bit = VMRuntime.getRuntime().is64Bit();
Primiano Tucci1b7977b2014-07-25 19:19:32 +0100405 try{
406 if (args.length != 2 || args[0] == null || args[1] == null) {
407 Log.e(LOGTAG, "Invalid RelroFileCreator args: " + Arrays.toString(args));
408 return;
409 }
Primiano Tucci1b7977b2014-07-25 19:19:32 +0100410 Log.v(LOGTAG, "RelroFileCreator (64bit = " + is64Bit + "), " +
411 " 32-bit lib: " + args[0] + ", 64-bit lib: " + args[1]);
412 if (!sAddressSpaceReserved) {
413 Log.e(LOGTAG, "can't create relro file; address space not reserved");
414 return;
415 }
Primiano Tucci161536b2014-07-28 18:51:45 +0100416 result = nativeCreateRelroFile(args[0] /* path32 */,
417 args[1] /* path64 */,
418 CHROMIUM_WEBVIEW_NATIVE_RELRO_32,
419 CHROMIUM_WEBVIEW_NATIVE_RELRO_64);
Primiano Tuccie76e81a2014-07-29 16:38:33 +0100420 if (result && DEBUG) Log.v(LOGTAG, "created relro file");
Primiano Tucci161536b2014-07-28 18:51:45 +0100421 } finally {
422 // We must do our best to always notify the update service, even if something fails.
Primiano Tucci1b7977b2014-07-25 19:19:32 +0100423 try {
424 getUpdateService().notifyRelroCreationCompleted(is64Bit, result);
425 } catch (RemoteException e) {
426 Log.e(LOGTAG, "error notifying update service", e);
427 }
Primiano Tucci161536b2014-07-28 18:51:45 +0100428
429 if (!result) Log.e(LOGTAG, "failed to create relro file");
430
Primiano Tucci1b7977b2014-07-25 19:19:32 +0100431 // Must explicitly exit or else this process will just sit around after we return.
432 System.exit(0);
433 }
Torne (Richard Coles)08cfaf62014-05-08 16:07:05 +0100434 }
435 }
436
437 private static void loadNativeLibrary() {
438 if (!sAddressSpaceReserved) {
439 Log.e(LOGTAG, "can't load with relro file; address space not reserved");
440 return;
441 }
442
443 try {
444 getUpdateService().waitForRelroCreationCompleted(VMRuntime.getRuntime().is64Bit());
445 } catch (RemoteException e) {
446 Log.e(LOGTAG, "error waiting for relro creation, proceeding without", e);
447 return;
448 }
449
Primiano Tucci1b7977b2014-07-25 19:19:32 +0100450 try {
451 String[] args = getWebViewNativeLibraryPaths();
452 boolean result = nativeLoadWithRelroFile(args[0] /* path32 */,
453 args[1] /* path64 */,
454 CHROMIUM_WEBVIEW_NATIVE_RELRO_32,
455 CHROMIUM_WEBVIEW_NATIVE_RELRO_64);
456 if (!result) {
457 Log.w(LOGTAG, "failed to load with relro file, proceeding without");
458 } else if (DEBUG) {
459 Log.v(LOGTAG, "loaded with relro file");
460 }
Gustav Senntona8366e72015-04-17 11:24:07 +0100461 } catch (MissingWebViewPackageException e) {
Primiano Tucci1b7977b2014-07-25 19:19:32 +0100462 Log.e(LOGTAG, "Failed to list WebView package libraries for loadNativeLibrary", e);
Torne (Richard Coles)08cfaf62014-05-08 16:07:05 +0100463 }
464 }
465
466 private static IWebViewUpdateService getUpdateService() {
467 return IWebViewUpdateService.Stub.asInterface(ServiceManager.getService("webviewupdate"));
468 }
469
Ben Murdoch5ced5022014-07-28 15:57:00 +0100470 private static native boolean nativeReserveAddressSpace(long addressSpaceToReserve);
Torne (Richard Coles)08cfaf62014-05-08 16:07:05 +0100471 private static native boolean nativeCreateRelroFile(String lib32, String lib64,
472 String relro32, String relro64);
473 private static native boolean nativeLoadWithRelroFile(String lib32, String lib64,
474 String relro32, String relro64);
Jonathan Dixond3101b12012-04-12 20:51:51 +0100475}