WebViewFactory.java revision fc424478a9e6c253238afe22ca174789d72e0682
1/* 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 19import android.annotation.SystemApi; 20import android.app.ActivityManagerInternal; 21import android.app.AppGlobals; 22import android.app.Application; 23import android.content.Context; 24import android.content.pm.ApplicationInfo; 25import android.content.pm.PackageInfo; 26import android.content.pm.PackageManager; 27import android.content.res.XmlResourceParser; 28import android.os.Build; 29import android.os.Process; 30import android.os.RemoteException; 31import android.os.ServiceManager; 32import android.os.StrictMode; 33import android.os.SystemProperties; 34import android.os.Trace; 35import android.provider.Settings; 36import android.provider.Settings.Secure; 37import android.text.TextUtils; 38import android.util.AndroidRuntimeException; 39import android.util.Log; 40 41import com.android.internal.util.XmlUtils; 42import com.android.server.LocalServices; 43 44import dalvik.system.VMRuntime; 45 46import java.io.File; 47import java.io.IOException; 48import java.util.ArrayList; 49import java.util.Arrays; 50import java.util.List; 51import java.util.zip.ZipEntry; 52import java.util.zip.ZipFile; 53 54import org.xmlpull.v1.XmlPullParserException; 55 56/** 57 * Top level factory, used creating all the main WebView implementation classes. 58 * 59 * @hide 60 */ 61@SystemApi 62public final class WebViewFactory { 63 64 private static final String CHROMIUM_WEBVIEW_FACTORY = 65 "com.android.webview.chromium.WebViewChromiumFactoryProvider"; 66 67 private static final String NULL_WEBVIEW_FACTORY = 68 "com.android.webview.nullwebview.NullWebViewFactoryProvider"; 69 70 private static final String CHROMIUM_WEBVIEW_NATIVE_RELRO_32 = 71 "/data/misc/shared_relro/libwebviewchromium32.relro"; 72 private static final String CHROMIUM_WEBVIEW_NATIVE_RELRO_64 = 73 "/data/misc/shared_relro/libwebviewchromium64.relro"; 74 75 public static final String CHROMIUM_WEBVIEW_VMSIZE_SIZE_PROPERTY = 76 "persist.sys.webview.vmsize"; 77 private static final long CHROMIUM_WEBVIEW_DEFAULT_VMSIZE_BYTES = 100 * 1024 * 1024; 78 79 private static final String LOGTAG = "WebViewFactory"; 80 81 private static final boolean DEBUG = false; 82 83 // Cache the factory both for efficiency, and ensure any one process gets all webviews from the 84 // same provider. 85 private static WebViewFactoryProvider sProviderInstance; 86 private static final Object sProviderLock = new Object(); 87 private static boolean sAddressSpaceReserved = false; 88 private static PackageInfo sPackageInfo; 89 90 // Error codes for loadWebViewNativeLibraryFromPackage 91 public static final int LIBLOAD_SUCCESS = 0; 92 public static final int LIBLOAD_WRONG_PACKAGE_NAME = 1; 93 public static final int LIBLOAD_ADDRESS_SPACE_NOT_RESERVED = 2; 94 95 // error codes for waiting for WebView preparation 96 public static final int LIBLOAD_FAILED_WAITING_FOR_RELRO = 3; 97 public static final int LIBLOAD_FAILED_LISTING_WEBVIEW_PACKAGES = 4; 98 99 // native relro loading error codes 100 public static final int LIBLOAD_FAILED_TO_OPEN_RELRO_FILE = 5; 101 public static final int LIBLOAD_FAILED_TO_LOAD_LIBRARY = 6; 102 public static final int LIBLOAD_FAILED_JNI_CALL = 7; 103 104 // more error codes for waiting for WebView preparation 105 public static final int LIBLOAD_WEBVIEW_BEING_REPLACED = 8; 106 public static final int LIBLOAD_FAILED_WAITING_FOR_WEBVIEW_REASON_UNKNOWN = 9; 107 108 private static String getWebViewPreparationErrorReason(int error) { 109 switch (error) { 110 case LIBLOAD_FAILED_WAITING_FOR_RELRO: 111 return "Time out waiting for Relro files being created"; 112 case LIBLOAD_FAILED_LISTING_WEBVIEW_PACKAGES: 113 return "No WebView installed"; 114 case LIBLOAD_WEBVIEW_BEING_REPLACED: 115 return "Time out waiting for WebView to be replaced"; 116 case LIBLOAD_FAILED_WAITING_FOR_WEBVIEW_REASON_UNKNOWN: 117 return "Crashed for unknown reason"; 118 } 119 return "Unknown"; 120 } 121 122 /** 123 * @hide 124 */ 125 public static class MissingWebViewPackageException extends AndroidRuntimeException { 126 public MissingWebViewPackageException(String message) { super(message); } 127 public MissingWebViewPackageException(Exception e) { super(e); } 128 } 129 130 private static String TAG_START = "webviewproviders"; 131 private static String TAG_WEBVIEW_PROVIDER = "webviewprovider"; 132 private static String TAG_PACKAGE_NAME = "packageName"; 133 private static String TAG_DESCRIPTION = "description"; 134 private static String TAG_SIGNATURE = "signature"; 135 136 /** 137 * Reads all signatures at the current depth (within the current provider) from the XML parser. 138 */ 139 private static String[] readSignatures(XmlResourceParser parser) throws IOException, 140 XmlPullParserException { 141 List<String> signatures = new ArrayList<String>(); 142 int outerDepth = parser.getDepth(); 143 while(XmlUtils.nextElementWithin(parser, outerDepth)) { 144 if (parser.getName().equals(TAG_SIGNATURE)) { 145 // Parse the value within the signature tag 146 String signature = parser.nextText(); 147 signatures.add(signature); 148 } else { 149 Log.e(LOGTAG, "Found an element in a webview provider that is not a signature"); 150 } 151 } 152 return signatures.toArray(new String[signatures.size()]); 153 } 154 155 /** 156 * Returns all packages declared in the framework resources as potential WebView providers. 157 * @hide 158 * */ 159 public static WebViewProviderInfo[] getWebViewPackages() { 160 XmlResourceParser parser = null; 161 List<WebViewProviderInfo> webViewProviders = new ArrayList<WebViewProviderInfo>(); 162 try { 163 parser = AppGlobals.getInitialApplication().getResources().getXml( 164 com.android.internal.R.xml.config_webview_packages); 165 XmlUtils.beginDocument(parser, TAG_START); 166 while(true) { 167 XmlUtils.nextElement(parser); 168 String element = parser.getName(); 169 if (element == null) { 170 break; 171 } 172 if (element.equals(TAG_WEBVIEW_PROVIDER)) { 173 String packageName = parser.getAttributeValue(null, TAG_PACKAGE_NAME); 174 if (packageName == null) { 175 throw new MissingWebViewPackageException( 176 "WebView provider in framework resources missing package name"); 177 } 178 String description = parser.getAttributeValue(null, TAG_DESCRIPTION); 179 if (description == null) { 180 throw new MissingWebViewPackageException( 181 "WebView provider in framework resources missing description"); 182 } 183 webViewProviders.add( 184 new WebViewProviderInfo(packageName, description, 185 readSignatures(parser))); 186 } 187 else { 188 Log.e(LOGTAG, "Found an element that is not a webview provider"); 189 } 190 } 191 } catch(XmlPullParserException e) { 192 throw new MissingWebViewPackageException("Error when parsing WebView meta data " + e); 193 } catch(IOException e) { 194 throw new MissingWebViewPackageException("Error when parsing WebView meta data " + e); 195 } finally { 196 if (parser != null) parser.close(); 197 } 198 return webViewProviders.toArray(new WebViewProviderInfo[webViewProviders.size()]); 199 } 200 201 202 // TODO (gsennton) remove when committing webview xts test change 203 public static String getWebViewPackageName() { 204 WebViewProviderInfo[] providers = getWebViewPackages(); 205 return providers[0].packageName; 206 } 207 208 /** 209 * @hide 210 */ 211 public static String getWebViewLibrary(ApplicationInfo ai) { 212 if (ai.metaData != null) 213 return ai.metaData.getString("com.android.webview.WebViewLibrary"); 214 return null; 215 } 216 217 public static PackageInfo getLoadedPackageInfo() { 218 return sPackageInfo; 219 } 220 221 /** 222 * Load the native library for the given package name iff that package 223 * name is the same as the one providing the webview. 224 */ 225 public static int loadWebViewNativeLibraryFromPackage(String packageName) { 226 int ret = waitForProviderAndSetPackageInfo(); 227 if (ret != LIBLOAD_SUCCESS) { 228 return ret; 229 } 230 if (!sPackageInfo.packageName.equals(packageName)) 231 return LIBLOAD_WRONG_PACKAGE_NAME; 232 233 return loadNativeLibrary(); 234 } 235 236 static WebViewFactoryProvider getProvider() { 237 synchronized (sProviderLock) { 238 // For now the main purpose of this function (and the factory abstraction) is to keep 239 // us honest and minimize usage of WebView internals when binding the proxy. 240 if (sProviderInstance != null) return sProviderInstance; 241 242 final int uid = android.os.Process.myUid(); 243 if (uid == android.os.Process.ROOT_UID || uid == android.os.Process.SYSTEM_UID) { 244 throw new UnsupportedOperationException( 245 "For security reasons, WebView is not allowed in privileged processes"); 246 } 247 248 Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "WebViewFactory.getProvider()"); 249 try { 250 Class<WebViewFactoryProvider> providerClass = getProviderClass(); 251 252 StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads(); 253 Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "providerClass.newInstance()"); 254 try { 255 sProviderInstance = providerClass.getConstructor(WebViewDelegate.class) 256 .newInstance(new WebViewDelegate()); 257 if (DEBUG) Log.v(LOGTAG, "Loaded provider: " + sProviderInstance); 258 return sProviderInstance; 259 } catch (Exception e) { 260 Log.e(LOGTAG, "error instantiating provider", e); 261 throw new AndroidRuntimeException(e); 262 } finally { 263 Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW); 264 StrictMode.setThreadPolicy(oldPolicy); 265 } 266 } finally { 267 Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW); 268 } 269 } 270 } 271 272 private static Class<WebViewFactoryProvider> getProviderClass() { 273 try { 274 Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, 275 "WebViewFactory.waitForProviderAndSetPackageInfo()"); 276 try { 277 // First fetch the package info so we can log the webview package version. 278 int res = waitForProviderAndSetPackageInfo(); 279 if (res != LIBLOAD_SUCCESS) { 280 throw new MissingWebViewPackageException( 281 "Failed to load WebView provider, error: " 282 + getWebViewPreparationErrorReason(res)); 283 } 284 } finally { 285 Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW); 286 } 287 Log.i(LOGTAG, "Loading " + sPackageInfo.packageName + " version " + 288 sPackageInfo.versionName + " (code " + sPackageInfo.versionCode + ")"); 289 290 Application initialApplication = AppGlobals.getInitialApplication(); 291 Context webViewContext = null; 292 Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "initialApplication.createPackageContext()"); 293 try { 294 // Construct a package context to load the Java code into the current app. 295 // This is done as early as possible since by constructing a package context we 296 // register the WebView package as a dependency for the current application so that 297 // when the WebView package is updated this application will be killed. 298 webViewContext = initialApplication.createPackageContext( 299 sPackageInfo.packageName, 300 Context.CONTEXT_INCLUDE_CODE | Context.CONTEXT_IGNORE_SECURITY); 301 } catch (PackageManager.NameNotFoundException e) { 302 throw new MissingWebViewPackageException(e); 303 } finally { 304 Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW); 305 } 306 307 Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "WebViewFactory.loadNativeLibrary()"); 308 loadNativeLibrary(); 309 Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW); 310 311 Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "WebViewFactory.getChromiumProviderClass()"); 312 try { 313 initialApplication.getAssets().addAssetPathAsSharedLibrary( 314 webViewContext.getApplicationInfo().sourceDir); 315 ClassLoader clazzLoader = webViewContext.getClassLoader(); 316 Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "Class.forName()"); 317 try { 318 return (Class<WebViewFactoryProvider>) Class.forName(CHROMIUM_WEBVIEW_FACTORY, 319 true, clazzLoader); 320 } finally { 321 Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW); 322 } 323 } catch (ClassNotFoundException e) { 324 Log.e(LOGTAG, "error loading provider", e); 325 throw new AndroidRuntimeException(e); 326 } finally { 327 Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW); 328 } 329 } catch (MissingWebViewPackageException e) { 330 // If the package doesn't exist, then try loading the null WebView instead. 331 // If that succeeds, then this is a device without WebView support; if it fails then 332 // swallow the failure, complain that the real WebView is missing and rethrow the 333 // original exception. 334 try { 335 return (Class<WebViewFactoryProvider>) Class.forName(NULL_WEBVIEW_FACTORY); 336 } catch (ClassNotFoundException e2) { 337 // Ignore. 338 } 339 Log.e(LOGTAG, "Chromium WebView package does not exist", e); 340 throw new AndroidRuntimeException(e); 341 } 342 } 343 344 /** 345 * Perform any WebView loading preparations that must happen in the zygote. 346 * Currently, this means allocating address space to load the real JNI library later. 347 */ 348 public static void prepareWebViewInZygote() { 349 try { 350 System.loadLibrary("webviewchromium_loader"); 351 long addressSpaceToReserve = 352 SystemProperties.getLong(CHROMIUM_WEBVIEW_VMSIZE_SIZE_PROPERTY, 353 CHROMIUM_WEBVIEW_DEFAULT_VMSIZE_BYTES); 354 sAddressSpaceReserved = nativeReserveAddressSpace(addressSpaceToReserve); 355 356 if (sAddressSpaceReserved) { 357 if (DEBUG) { 358 Log.v(LOGTAG, "address space reserved: " + addressSpaceToReserve + " bytes"); 359 } 360 } else { 361 Log.e(LOGTAG, "reserving " + addressSpaceToReserve + 362 " bytes of address space failed"); 363 } 364 } catch (Throwable t) { 365 // Log and discard errors at this stage as we must not crash the zygote. 366 Log.e(LOGTAG, "error preparing native loader", t); 367 } 368 } 369 370 private static int prepareWebViewInSystemServer(String[] nativeLibraryPaths) { 371 if (DEBUG) Log.v(LOGTAG, "creating relro files"); 372 int numRelros = 0; 373 374 // We must always trigger createRelRo regardless of the value of nativeLibraryPaths. Any 375 // unexpected values will be handled there to ensure that we trigger notifying any process 376 // waiting on relro creation. 377 if (Build.SUPPORTED_32_BIT_ABIS.length > 0) { 378 if (DEBUG) Log.v(LOGTAG, "Create 32 bit relro"); 379 createRelroFile(false /* is64Bit */, nativeLibraryPaths); 380 numRelros++; 381 } 382 383 if (Build.SUPPORTED_64_BIT_ABIS.length > 0) { 384 if (DEBUG) Log.v(LOGTAG, "Create 64 bit relro"); 385 createRelroFile(true /* is64Bit */, nativeLibraryPaths); 386 numRelros++; 387 } 388 return numRelros; 389 } 390 391 /** 392 * @hide 393 */ 394 public static int onWebViewProviderChanged(PackageInfo packageInfo) { 395 String[] nativeLibs = null; 396 try { 397 nativeLibs = WebViewFactory.getWebViewNativeLibraryPaths(packageInfo); 398 if (nativeLibs != null) { 399 long newVmSize = 0L; 400 401 for (String path : nativeLibs) { 402 if (path == null || TextUtils.isEmpty(path)) continue; 403 if (DEBUG) Log.d(LOGTAG, "Checking file size of " + path); 404 File f = new File(path); 405 if (f.exists()) { 406 newVmSize = Math.max(newVmSize, f.length()); 407 continue; 408 } 409 if (path.contains("!/")) { 410 String[] split = TextUtils.split(path, "!/"); 411 if (split.length == 2) { 412 try (ZipFile z = new ZipFile(split[0])) { 413 ZipEntry e = z.getEntry(split[1]); 414 if (e != null && e.getMethod() == ZipEntry.STORED) { 415 newVmSize = Math.max(newVmSize, e.getSize()); 416 continue; 417 } 418 } 419 catch (IOException e) { 420 Log.e(LOGTAG, "error reading APK file " + split[0] + ", ", e); 421 } 422 } 423 } 424 Log.e(LOGTAG, "error sizing load for " + path); 425 } 426 427 if (DEBUG) { 428 Log.v(LOGTAG, "Based on library size, need " + newVmSize + 429 " bytes of address space."); 430 } 431 // The required memory can be larger than the file on disk (due to .bss), and an 432 // upgraded version of the library will likely be larger, so always attempt to 433 // reserve twice as much as we think to allow for the library to grow during this 434 // boot cycle. 435 newVmSize = Math.max(2 * newVmSize, CHROMIUM_WEBVIEW_DEFAULT_VMSIZE_BYTES); 436 Log.d(LOGTAG, "Setting new address space to " + newVmSize); 437 SystemProperties.set(CHROMIUM_WEBVIEW_VMSIZE_SIZE_PROPERTY, 438 Long.toString(newVmSize)); 439 } 440 } catch (Throwable t) { 441 // Log and discard errors at this stage as we must not crash the system server. 442 Log.e(LOGTAG, "error preparing webview native library", t); 443 } 444 return prepareWebViewInSystemServer(nativeLibs); 445 } 446 447 // throws MissingWebViewPackageException 448 private static String getLoadFromApkPath(String apkPath, 449 String[] abiList, 450 String nativeLibFileName) { 451 // Search the APK for a native library conforming to a listed ABI. 452 try (ZipFile z = new ZipFile(apkPath)) { 453 for (String abi : abiList) { 454 final String entry = "lib/" + abi + "/" + nativeLibFileName; 455 ZipEntry e = z.getEntry(entry); 456 if (e != null && e.getMethod() == ZipEntry.STORED) { 457 // Return a path formatted for dlopen() load from APK. 458 return apkPath + "!/" + entry; 459 } 460 } 461 } catch (IOException e) { 462 throw new MissingWebViewPackageException(e); 463 } 464 return ""; 465 } 466 467 // throws MissingWebViewPackageException 468 private static String[] getWebViewNativeLibraryPaths(PackageInfo packageInfo) { 469 ApplicationInfo ai = packageInfo.applicationInfo; 470 final String NATIVE_LIB_FILE_NAME = getWebViewLibrary(ai); 471 472 String path32; 473 String path64; 474 boolean primaryArchIs64bit = VMRuntime.is64BitAbi(ai.primaryCpuAbi); 475 if (!TextUtils.isEmpty(ai.secondaryCpuAbi)) { 476 // Multi-arch case. 477 if (primaryArchIs64bit) { 478 // Primary arch: 64-bit, secondary: 32-bit. 479 path64 = ai.nativeLibraryDir; 480 path32 = ai.secondaryNativeLibraryDir; 481 } else { 482 // Primary arch: 32-bit, secondary: 64-bit. 483 path64 = ai.secondaryNativeLibraryDir; 484 path32 = ai.nativeLibraryDir; 485 } 486 } else if (primaryArchIs64bit) { 487 // Single-arch 64-bit. 488 path64 = ai.nativeLibraryDir; 489 path32 = ""; 490 } else { 491 // Single-arch 32-bit. 492 path32 = ai.nativeLibraryDir; 493 path64 = ""; 494 } 495 496 // Form the full paths to the extracted native libraries. 497 // If libraries were not extracted, try load from APK paths instead. 498 if (!TextUtils.isEmpty(path32)) { 499 path32 += "/" + NATIVE_LIB_FILE_NAME; 500 File f = new File(path32); 501 if (!f.exists()) { 502 path32 = getLoadFromApkPath(ai.sourceDir, 503 Build.SUPPORTED_32_BIT_ABIS, 504 NATIVE_LIB_FILE_NAME); 505 } 506 } 507 if (!TextUtils.isEmpty(path64)) { 508 path64 += "/" + NATIVE_LIB_FILE_NAME; 509 File f = new File(path64); 510 if (!f.exists()) { 511 path64 = getLoadFromApkPath(ai.sourceDir, 512 Build.SUPPORTED_64_BIT_ABIS, 513 NATIVE_LIB_FILE_NAME); 514 } 515 } 516 517 if (DEBUG) Log.v(LOGTAG, "Native 32-bit lib: " + path32 + ", 64-bit lib: " + path64); 518 return new String[] { path32, path64 }; 519 } 520 521 private static void createRelroFile(final boolean is64Bit, String[] nativeLibraryPaths) { 522 final String abi = 523 is64Bit ? Build.SUPPORTED_64_BIT_ABIS[0] : Build.SUPPORTED_32_BIT_ABIS[0]; 524 525 // crashHandler is invoked by the ActivityManagerService when the isolated process crashes. 526 Runnable crashHandler = new Runnable() { 527 @Override 528 public void run() { 529 try { 530 Log.e(LOGTAG, "relro file creator for " + abi + " crashed. Proceeding without"); 531 getUpdateService().notifyRelroCreationCompleted(); 532 } catch (RemoteException e) { 533 Log.e(LOGTAG, "Cannot reach WebViewUpdateService. " + e.getMessage()); 534 } 535 } 536 }; 537 538 try { 539 if (nativeLibraryPaths == null 540 || nativeLibraryPaths[0] == null || nativeLibraryPaths[1] == null) { 541 throw new IllegalArgumentException( 542 "Native library paths to the WebView RelRo process must not be null!"); 543 } 544 int pid = LocalServices.getService(ActivityManagerInternal.class).startIsolatedProcess( 545 RelroFileCreator.class.getName(), nativeLibraryPaths, "WebViewLoader-" + abi, abi, 546 Process.SHARED_RELRO_UID, crashHandler); 547 if (pid <= 0) throw new Exception("Failed to start the relro file creator process"); 548 } catch (Throwable t) { 549 // Log and discard errors as we must not crash the system server. 550 Log.e(LOGTAG, "error starting relro file creator for abi " + abi, t); 551 crashHandler.run(); 552 } 553 } 554 555 private static class RelroFileCreator { 556 // Called in an unprivileged child process to create the relro file. 557 public static void main(String[] args) { 558 boolean result = false; 559 boolean is64Bit = VMRuntime.getRuntime().is64Bit(); 560 try{ 561 if (args.length != 2 || args[0] == null || args[1] == null) { 562 Log.e(LOGTAG, "Invalid RelroFileCreator args: " + Arrays.toString(args)); 563 return; 564 } 565 Log.v(LOGTAG, "RelroFileCreator (64bit = " + is64Bit + "), " + 566 " 32-bit lib: " + args[0] + ", 64-bit lib: " + args[1]); 567 if (!sAddressSpaceReserved) { 568 Log.e(LOGTAG, "can't create relro file; address space not reserved"); 569 return; 570 } 571 result = nativeCreateRelroFile(args[0] /* path32 */, 572 args[1] /* path64 */, 573 CHROMIUM_WEBVIEW_NATIVE_RELRO_32, 574 CHROMIUM_WEBVIEW_NATIVE_RELRO_64); 575 if (result && DEBUG) Log.v(LOGTAG, "created relro file"); 576 } finally { 577 // We must do our best to always notify the update service, even if something fails. 578 try { 579 getUpdateService().notifyRelroCreationCompleted(); 580 } catch (RemoteException e) { 581 Log.e(LOGTAG, "error notifying update service", e); 582 } 583 584 if (!result) Log.e(LOGTAG, "failed to create relro file"); 585 586 // Must explicitly exit or else this process will just sit around after we return. 587 System.exit(0); 588 } 589 } 590 } 591 592 private static int waitForProviderAndSetPackageInfo() { 593 WebViewProviderResponse response = null; 594 try { 595 response = 596 getUpdateService().waitForAndGetProvider(); 597 if (response.status == WebViewFactory.LIBLOAD_SUCCESS) 598 sPackageInfo = response.packageInfo; 599 } catch (RemoteException e) { 600 Log.e(LOGTAG, "error waiting for relro creation", e); 601 return LIBLOAD_FAILED_WAITING_FOR_WEBVIEW_REASON_UNKNOWN; 602 } 603 return response.status; 604 } 605 606 // Assumes that we have waited for relro creation and set sPackageInfo 607 private static int loadNativeLibrary() { 608 if (!sAddressSpaceReserved) { 609 Log.e(LOGTAG, "can't load with relro file; address space not reserved"); 610 return LIBLOAD_ADDRESS_SPACE_NOT_RESERVED; 611 } 612 613 String[] args = getWebViewNativeLibraryPaths(sPackageInfo); 614 int result = nativeLoadWithRelroFile(args[0] /* path32 */, 615 args[1] /* path64 */, 616 CHROMIUM_WEBVIEW_NATIVE_RELRO_32, 617 CHROMIUM_WEBVIEW_NATIVE_RELRO_64); 618 if (result != LIBLOAD_SUCCESS) { 619 Log.w(LOGTAG, "failed to load with relro file, proceeding without"); 620 } else if (DEBUG) { 621 Log.v(LOGTAG, "loaded with relro file"); 622 } 623 return result; 624 } 625 626 private static IWebViewUpdateService getUpdateService() { 627 return IWebViewUpdateService.Stub.asInterface(ServiceManager.getService("webviewupdate")); 628 } 629 630 private static native boolean nativeReserveAddressSpace(long addressSpaceToReserve); 631 private static native boolean nativeCreateRelroFile(String lib32, String lib64, 632 String relro32, String relro64); 633 private static native int nativeLoadWithRelroFile(String lib32, String lib64, 634 String relro32, String relro64); 635} 636