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