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