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 
17 package android.webkit;
18 
19 import static android.webkit.Flags.updateServiceV2;
20 
21 import android.annotation.NonNull;
22 import android.annotation.SystemApi;
23 import android.annotation.UptimeMillisLong;
24 import android.app.ActivityManager;
25 import android.app.AppGlobals;
26 import android.app.Application;
27 import android.compat.annotation.UnsupportedAppUsage;
28 import android.content.Context;
29 import android.content.pm.ApplicationInfo;
30 import android.content.pm.PackageInfo;
31 import android.content.pm.PackageManager;
32 import android.content.pm.Signature;
33 import android.content.res.Resources;
34 import android.os.Build;
35 import android.os.RemoteException;
36 import android.os.ServiceManager;
37 import android.os.SystemClock;
38 import android.os.Trace;
39 import android.text.TextUtils;
40 import android.util.AndroidRuntimeException;
41 import android.util.ArraySet;
42 import android.util.Log;
43 import android.util.Slog;
44 
45 import java.io.File;
46 import java.lang.reflect.Method;
47 
48 /**
49  * Top level factory, used creating all the main WebView implementation classes.
50  *
51  * @hide
52  */
53 @SystemApi
54 public final class WebViewFactory {
55 
56     // visible for WebViewZygoteInit to look up the class by reflection and call preloadInZygote.
57     /** @hide */
58     private static final String CHROMIUM_WEBVIEW_FACTORY =
59             "com.android.webview.chromium.WebViewChromiumFactoryProviderForT";
60 
61     private static final String CHROMIUM_WEBVIEW_FACTORY_METHOD = "create";
62 
63     private static final String LOGTAG = "WebViewFactory";
64 
65     private static final boolean DEBUG = false;
66 
67     // Cache the factory both for efficiency, and ensure any one process gets all webviews from the
68     // same provider.
69     @UnsupportedAppUsage
70     private static WebViewFactoryProvider sProviderInstance;
71     private static final Object sProviderLock = new Object();
72     @UnsupportedAppUsage
73     private static PackageInfo sPackageInfo;
74     private static Boolean sWebViewSupported;
75     private static boolean sWebViewDisabled;
76     private static String sDataDirectorySuffix; // stored here so it can be set without loading WV
77 
78     // Error codes for loadWebViewNativeLibraryFromPackage
79     public static final int LIBLOAD_SUCCESS = 0;
80     public static final int LIBLOAD_WRONG_PACKAGE_NAME = 1;
81     public static final int LIBLOAD_ADDRESS_SPACE_NOT_RESERVED = 2;
82 
83     // error codes for waiting for WebView preparation
84     public static final int LIBLOAD_FAILED_WAITING_FOR_RELRO = 3;
85     public static final int LIBLOAD_FAILED_LISTING_WEBVIEW_PACKAGES = 4;
86 
87     // native relro loading error codes
88     public static final int LIBLOAD_FAILED_TO_OPEN_RELRO_FILE = 5;
89     public static final int LIBLOAD_FAILED_TO_LOAD_LIBRARY = 6;
90     public static final int LIBLOAD_FAILED_JNI_CALL = 7;
91 
92     // more error codes for waiting for WebView preparation
93     public static final int LIBLOAD_FAILED_WAITING_FOR_WEBVIEW_REASON_UNKNOWN = 8;
94 
95     // error for namespace lookup
96     public static final int LIBLOAD_FAILED_TO_FIND_NAMESPACE = 10;
97 
98     // generic error for future use
99     static final int LIBLOAD_FAILED_OTHER = 11;
100 
101     /**
102      * Stores the timestamps at which various WebView startup events occurred in this process.
103      */
104     public static class StartupTimestamps {
105         long mWebViewLoadStart;
106         long mCreateContextStart;
107         long mCreateContextEnd;
108         long mAddAssetsStart;
109         long mAddAssetsEnd;
110         long mGetClassLoaderStart;
111         long mGetClassLoaderEnd;
112         long mNativeLoadStart;
113         long mNativeLoadEnd;
114         long mProviderClassForNameStart;
115         long mProviderClassForNameEnd;
116 
StartupTimestamps()117         StartupTimestamps() {}
118 
119         /** When the overall WebView provider load began. */
120         @UptimeMillisLong
getWebViewLoadStart()121         public long getWebViewLoadStart() {
122             return mWebViewLoadStart;
123         }
124 
125         /** Before creating the WebView APK Context. */
126         @UptimeMillisLong
getCreateContextStart()127         public long getCreateContextStart() {
128             return mCreateContextStart;
129         }
130 
131         /** After creating the WebView APK Context. */
132         @UptimeMillisLong
getCreateContextEnd()133         public long getCreateContextEnd() {
134             return mCreateContextEnd;
135         }
136 
137         /** Before adding WebView assets to AssetManager. */
138         @UptimeMillisLong
getAddAssetsStart()139         public long getAddAssetsStart() {
140             return mAddAssetsStart;
141         }
142 
143         /** After adding WebView assets to AssetManager. */
144         @UptimeMillisLong
getAddAssetsEnd()145         public long getAddAssetsEnd() {
146             return mAddAssetsEnd;
147         }
148 
149         /** Before creating the WebView ClassLoader. */
150         @UptimeMillisLong
getGetClassLoaderStart()151         public long getGetClassLoaderStart() {
152             return mGetClassLoaderStart;
153         }
154 
155         /** After creating the WebView ClassLoader. */
156         @UptimeMillisLong
getGetClassLoaderEnd()157         public long getGetClassLoaderEnd() {
158             return mGetClassLoaderEnd;
159         }
160 
161         /** Before preloading the WebView native library. */
162         @UptimeMillisLong
getNativeLoadStart()163         public long getNativeLoadStart() {
164             return mNativeLoadStart;
165         }
166 
167         /** After preloading the WebView native library. */
168         @UptimeMillisLong
getNativeLoadEnd()169         public long getNativeLoadEnd() {
170             return mNativeLoadEnd;
171         }
172 
173         /** Before looking up the WebView provider class. */
174         @UptimeMillisLong
getProviderClassForNameStart()175         public long getProviderClassForNameStart() {
176             return mProviderClassForNameStart;
177         }
178 
179         /** After looking up the WebView provider class. */
180         @UptimeMillisLong
getProviderClassForNameEnd()181         public long getProviderClassForNameEnd() {
182             return mProviderClassForNameEnd;
183         }
184     }
185 
186     static final StartupTimestamps sTimestamps = new StartupTimestamps();
187 
188     @NonNull
getStartupTimestamps()189     static StartupTimestamps getStartupTimestamps() {
190         return sTimestamps;
191     }
192 
getWebViewPreparationErrorReason(int error)193     private static String getWebViewPreparationErrorReason(int error) {
194         switch (error) {
195             case LIBLOAD_FAILED_WAITING_FOR_RELRO:
196                 return "Time out waiting for Relro files being created";
197             case LIBLOAD_FAILED_LISTING_WEBVIEW_PACKAGES:
198                 return "No WebView installed";
199             case LIBLOAD_FAILED_WAITING_FOR_WEBVIEW_REASON_UNKNOWN:
200                 return "Crashed for unknown reason";
201         }
202         return "Unknown";
203     }
204 
205     static class MissingWebViewPackageException extends Exception {
MissingWebViewPackageException(String message)206         public MissingWebViewPackageException(String message) { super(message); }
MissingWebViewPackageException(Exception e)207         public MissingWebViewPackageException(Exception e) { super(e); }
208     }
209 
isWebViewSupported()210     private static boolean isWebViewSupported() {
211         // No lock; this is a benign race as Boolean's state is final and the PackageManager call
212         // will always return the same value.
213         if (sWebViewSupported == null) {
214             sWebViewSupported = AppGlobals.getInitialApplication().getPackageManager()
215                     .hasSystemFeature(PackageManager.FEATURE_WEBVIEW);
216         }
217         return sWebViewSupported;
218     }
219 
220     /**
221      * @hide
222      */
disableWebView()223     static void disableWebView() {
224         synchronized (sProviderLock) {
225             if (sProviderInstance != null) {
226                 throw new IllegalStateException(
227                         "Can't disable WebView: WebView already initialized");
228             }
229             sWebViewDisabled = true;
230         }
231     }
232 
233     /**
234      * @hide
235      */
setDataDirectorySuffix(String suffix)236     static void setDataDirectorySuffix(String suffix) {
237         synchronized (sProviderLock) {
238             if (sProviderInstance != null) {
239                 throw new IllegalStateException(
240                         "Can't set data directory suffix: WebView already initialized");
241             }
242             if (suffix.indexOf(File.separatorChar) >= 0) {
243                 throw new IllegalArgumentException("Suffix " + suffix
244                                                    + " contains a path separator");
245             }
246             sDataDirectorySuffix = suffix;
247         }
248     }
249 
250     /**
251      * @hide
252      */
getDataDirectorySuffix()253     static String getDataDirectorySuffix() {
254         synchronized (sProviderLock) {
255             return sDataDirectorySuffix;
256         }
257     }
258 
259     /**
260      * @hide
261      */
getWebViewLibrary(ApplicationInfo ai)262     public static String getWebViewLibrary(ApplicationInfo ai) {
263         if (ai.metaData != null)
264             return ai.metaData.getString("com.android.webview.WebViewLibrary");
265         return null;
266     }
267 
getLoadedPackageInfo()268     public static PackageInfo getLoadedPackageInfo() {
269         synchronized (sProviderLock) {
270             return sPackageInfo;
271         }
272     }
273 
274     /**
275      * @hide
276      */
getWebViewProviderClass(ClassLoader clazzLoader)277     public static Class<WebViewFactoryProvider> getWebViewProviderClass(ClassLoader clazzLoader)
278             throws ClassNotFoundException {
279         return (Class<WebViewFactoryProvider>) Class.forName(CHROMIUM_WEBVIEW_FACTORY,
280                 true, clazzLoader);
281     }
282 
283     /**
284      * Load the native library for the given package name if that package
285      * name is the same as the one providing the webview.
286      */
loadWebViewNativeLibraryFromPackage(String packageName, ClassLoader clazzLoader)287     public static int loadWebViewNativeLibraryFromPackage(String packageName,
288                                                           ClassLoader clazzLoader) {
289         if (!isWebViewSupported()) {
290             return LIBLOAD_WRONG_PACKAGE_NAME;
291         }
292 
293         Application initialApplication = AppGlobals.getInitialApplication();
294         WebViewProviderResponse response = null;
295         try {
296             if (Flags.updateServiceIpcWrapper()) {
297                 response = initialApplication.getSystemService(WebViewUpdateManager.class)
298                         .waitForAndGetProvider();
299             } else {
300                 response = getUpdateService().waitForAndGetProvider();
301             }
302         } catch (Exception e) {
303             Log.e(LOGTAG, "error waiting for relro creation", e);
304             return LIBLOAD_FAILED_WAITING_FOR_WEBVIEW_REASON_UNKNOWN;
305         }
306 
307 
308         if (response.status != LIBLOAD_SUCCESS
309                 && response.status != LIBLOAD_FAILED_WAITING_FOR_RELRO) {
310             return response.status;
311         }
312         if (!response.packageInfo.packageName.equals(packageName)) {
313             return LIBLOAD_WRONG_PACKAGE_NAME;
314         }
315 
316         PackageManager packageManager = initialApplication.getPackageManager();
317         String libraryFileName;
318         try {
319             PackageInfo packageInfo = packageManager.getPackageInfo(packageName,
320                     PackageManager.GET_META_DATA | PackageManager.MATCH_DEBUG_TRIAGED_MISSING);
321             libraryFileName = getWebViewLibrary(packageInfo.applicationInfo);
322         } catch (PackageManager.NameNotFoundException e) {
323             Log.e(LOGTAG, "Couldn't find package " + packageName);
324             return LIBLOAD_WRONG_PACKAGE_NAME;
325         }
326 
327         int loadNativeRet = WebViewLibraryLoader.loadNativeLibrary(clazzLoader, libraryFileName);
328         // If we failed waiting for relro we want to return that fact even if we successfully
329         // load the relro file.
330         if (loadNativeRet == LIBLOAD_SUCCESS) return response.status;
331         return loadNativeRet;
332     }
333 
334     @UnsupportedAppUsage
getProvider()335     static WebViewFactoryProvider getProvider() {
336         synchronized (sProviderLock) {
337             // For now the main purpose of this function (and the factory abstraction) is to keep
338             // us honest and minimize usage of WebView internals when binding the proxy.
339             if (sProviderInstance != null) return sProviderInstance;
340 
341             sTimestamps.mWebViewLoadStart = SystemClock.uptimeMillis();
342             final int uid = android.os.Process.myUid();
343             if (uid == android.os.Process.ROOT_UID || uid == android.os.Process.SYSTEM_UID
344                     || uid == android.os.Process.PHONE_UID || uid == android.os.Process.NFC_UID
345                     || uid == android.os.Process.BLUETOOTH_UID) {
346                 throw new UnsupportedOperationException(
347                         "For security reasons, WebView is not allowed in privileged processes");
348             }
349 
350             if (!isWebViewSupported()) {
351                 // Device doesn't support WebView; don't try to load it, just throw.
352                 throw new UnsupportedOperationException();
353             }
354 
355             if (sWebViewDisabled) {
356                 throw new IllegalStateException(
357                         "WebView.disableWebView() was called: WebView is disabled");
358             }
359 
360             Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "WebViewFactory.getProvider()");
361             try {
362                 Class<WebViewFactoryProvider> providerClass = getProviderClass();
363                 Method staticFactory = providerClass.getMethod(
364                         CHROMIUM_WEBVIEW_FACTORY_METHOD, WebViewDelegate.class);
365 
366                 Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "WebViewFactoryProvider invocation");
367                 try {
368                     sProviderInstance = (WebViewFactoryProvider)
369                             staticFactory.invoke(null, new WebViewDelegate());
370                     if (DEBUG) Log.v(LOGTAG, "Loaded provider: " + sProviderInstance);
371                     return sProviderInstance;
372                 } finally {
373                     Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW);
374                 }
375             } catch (Exception e) {
376                 Log.e(LOGTAG, "error instantiating provider", e);
377                 throw new AndroidRuntimeException(e);
378             } finally {
379                 Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW);
380             }
381         }
382     }
383 
384     /**
385      * Returns {@code true} if the signatures match, {@code false} otherwise
386      */
signaturesEquals(Signature[] s1, Signature[] s2)387     private static boolean signaturesEquals(Signature[] s1, Signature[] s2) {
388         if (s1 == null) {
389             return s2 == null;
390         }
391         if (s2 == null) return false;
392 
393         ArraySet<Signature> set1 = new ArraySet<>();
394         for(Signature signature : s1) {
395             set1.add(signature);
396         }
397         ArraySet<Signature> set2 = new ArraySet<>();
398         for(Signature signature : s2) {
399             set2.add(signature);
400         }
401         return set1.equals(set2);
402     }
403 
404     // Throws MissingWebViewPackageException on failure
verifyPackageInfo(PackageInfo chosen, PackageInfo toUse)405     private static void verifyPackageInfo(PackageInfo chosen, PackageInfo toUse)
406             throws MissingWebViewPackageException {
407         if (!chosen.packageName.equals(toUse.packageName)) {
408             throw new MissingWebViewPackageException("Failed to verify WebView provider, "
409                     + "packageName mismatch, expected: "
410                     + chosen.packageName + " actual: " + toUse.packageName);
411         }
412         if (chosen.getLongVersionCode() > toUse.getLongVersionCode()) {
413             throw new MissingWebViewPackageException("Failed to verify WebView provider, "
414                     + "version code is lower than expected: " + chosen.getLongVersionCode()
415                     + " actual: " + toUse.getLongVersionCode());
416         }
417         if (getWebViewLibrary(toUse.applicationInfo) == null) {
418             throw new MissingWebViewPackageException("Tried to load an invalid WebView provider: "
419                     + toUse.packageName);
420         }
421         if (!signaturesEquals(chosen.signatures, toUse.signatures)) {
422             throw new MissingWebViewPackageException("Failed to verify WebView provider, "
423                     + "signature mismatch");
424         }
425     }
426 
427     // Returns whether the given package is enabled.
428     // This state can be changed by the user from Settings->Apps
isEnabledPackage(PackageInfo packageInfo)429     private static boolean isEnabledPackage(PackageInfo packageInfo) {
430         if (packageInfo == null) return false;
431         return packageInfo.applicationInfo.enabled;
432     }
433 
434     // Return {@code true} if the package is installed and not hidden
isInstalledPackage(PackageInfo packageInfo)435     private static boolean isInstalledPackage(PackageInfo packageInfo) {
436         if (packageInfo == null) return false;
437         return (((packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_INSTALLED) != 0)
438                 && ((packageInfo.applicationInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_HIDDEN)
439                         == 0));
440     }
441 
442     @UnsupportedAppUsage
getWebViewContextAndSetProvider()443     private static Context getWebViewContextAndSetProvider() throws MissingWebViewPackageException {
444         Application initialApplication = AppGlobals.getInitialApplication();
445         try {
446             WebViewProviderResponse response = null;
447             Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW,
448                     "WebViewUpdateService.waitForAndGetProvider()");
449             try {
450                 if (Flags.updateServiceIpcWrapper()) {
451                     response = initialApplication.getSystemService(WebViewUpdateManager.class)
452                             .waitForAndGetProvider();
453                 } else {
454                     response = getUpdateService().waitForAndGetProvider();
455                 }
456             } finally {
457                 Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW);
458             }
459             if (response.status != LIBLOAD_SUCCESS
460                     && response.status != LIBLOAD_FAILED_WAITING_FOR_RELRO) {
461                 throw new MissingWebViewPackageException("Failed to load WebView provider: "
462                         + getWebViewPreparationErrorReason(response.status));
463             }
464             // Register to be killed before fetching package info - so that we will be
465             // killed if the package info goes out-of-date.
466             Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "ActivityManager.addPackageDependency()");
467             try {
468                 ActivityManager.getService().addPackageDependency(
469                         response.packageInfo.packageName);
470             } finally {
471                 Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW);
472             }
473             // Fetch package info and verify it against the chosen package
474             PackageInfo newPackageInfo = null;
475             PackageManager pm = initialApplication.getPackageManager();
476             Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "PackageManager.getPackageInfo()");
477             try {
478                 newPackageInfo = pm.getPackageInfo(
479                     response.packageInfo.packageName,
480                     PackageManager.GET_SHARED_LIBRARY_FILES
481                     | PackageManager.MATCH_DEBUG_TRIAGED_MISSING
482                     // Make sure that we fetch the current provider even if its not
483                     // installed for the current user
484                     | PackageManager.MATCH_UNINSTALLED_PACKAGES
485                     // Fetch signatures for verification
486                     | PackageManager.GET_SIGNATURES
487                     // Get meta-data for meta data flag verification
488                     | PackageManager.GET_META_DATA);
489             } finally {
490                 Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW);
491             }
492 
493             if (updateServiceV2() && !isInstalledPackage(newPackageInfo)) {
494                 throw new MissingWebViewPackageException(
495                         TextUtils.formatSimple(
496                                 "Current WebView Package (%s) is not installed for the current "
497                                 + "user",
498                                 newPackageInfo.packageName));
499             }
500 
501             if (updateServiceV2() && !isEnabledPackage(newPackageInfo)) {
502                 throw new MissingWebViewPackageException(
503                         TextUtils.formatSimple(
504                                 "Current WebView Package (%s) is not enabled for the current user",
505                                 newPackageInfo.packageName));
506             }
507 
508             // Validate the newly fetched package info, throws MissingWebViewPackageException on
509             // failure
510             verifyPackageInfo(response.packageInfo, newPackageInfo);
511 
512             ApplicationInfo ai = newPackageInfo.applicationInfo;
513 
514             Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW,
515                     "initialApplication.createApplicationContext");
516             sTimestamps.mCreateContextStart = SystemClock.uptimeMillis();
517             try {
518                 // Construct an app context to load the Java code into the current app.
519                 Context webViewContext = initialApplication.createApplicationContext(
520                         ai,
521                         Context.CONTEXT_INCLUDE_CODE | Context.CONTEXT_IGNORE_SECURITY);
522                 sPackageInfo = newPackageInfo;
523                 return webViewContext;
524             } finally {
525                 sTimestamps.mCreateContextEnd = SystemClock.uptimeMillis();
526                 Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW);
527             }
528         } catch (RemoteException | PackageManager.NameNotFoundException e) {
529             throw new MissingWebViewPackageException("Failed to load WebView provider: " + e);
530         }
531     }
532 
533     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
getProviderClass()534     private static Class<WebViewFactoryProvider> getProviderClass() {
535         Context webViewContext = null;
536         Application initialApplication = AppGlobals.getInitialApplication();
537 
538         try {
539             Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW,
540                     "WebViewFactory.getWebViewContextAndSetProvider()");
541             try {
542                 webViewContext = getWebViewContextAndSetProvider();
543             } finally {
544                 Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW);
545             }
546             Log.i(LOGTAG, "Loading " + sPackageInfo.packageName + " version " +
547                     sPackageInfo.versionName + " (code " + sPackageInfo.getLongVersionCode() + ")");
548 
549             Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "WebViewFactory.getChromiumProviderClass()");
550             try {
551                 sTimestamps.mAddAssetsStart = SystemClock.uptimeMillis();
552                 if (android.content.res.Flags.registerResourcePaths()) {
553                     Resources.registerResourcePaths(webViewContext.getPackageName(),
554                             webViewContext.getApplicationInfo());
555                 } else {
556                     for (String newAssetPath : webViewContext.getApplicationInfo()
557                             .getAllApkPaths()) {
558                         initialApplication.getAssets().addAssetPathAsSharedLibrary(newAssetPath);
559                     }
560                 }
561                 sTimestamps.mAddAssetsEnd = sTimestamps.mGetClassLoaderStart =
562                         SystemClock.uptimeMillis();
563                 ClassLoader clazzLoader = webViewContext.getClassLoader();
564                 Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "WebViewFactory.loadNativeLibrary()");
565                 sTimestamps.mGetClassLoaderEnd = sTimestamps.mNativeLoadStart =
566                         SystemClock.uptimeMillis();
567                 WebViewLibraryLoader.loadNativeLibrary(clazzLoader,
568                         getWebViewLibrary(sPackageInfo.applicationInfo));
569                 Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW);
570                 Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "Class.forName()");
571                 sTimestamps.mNativeLoadEnd = sTimestamps.mProviderClassForNameStart =
572                         SystemClock.uptimeMillis();
573                 try {
574                     return getWebViewProviderClass(clazzLoader);
575                 } finally {
576                     sTimestamps.mProviderClassForNameEnd = SystemClock.uptimeMillis();
577                     Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW);
578                 }
579             } catch (ClassNotFoundException e) {
580                 Log.e(LOGTAG, "error loading provider", e);
581                 throw new AndroidRuntimeException(e);
582             } finally {
583                 Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW);
584             }
585         } catch (MissingWebViewPackageException e) {
586             Log.e(LOGTAG, "Chromium WebView package does not exist", e);
587             throw new AndroidRuntimeException(e);
588         }
589     }
590 
591     /**
592      * Perform any WebView loading preparations that must happen in the zygote.
593      * Currently, this means allocating address space to load the real JNI library later.
594      */
prepareWebViewInZygote()595     public static void prepareWebViewInZygote() {
596         try {
597             WebViewLibraryLoader.reserveAddressSpaceInZygote();
598         } catch (Throwable t) {
599             // Log and discard errors at this stage as we must not crash the zygote.
600             Log.e(LOGTAG, "error preparing native loader", t);
601         }
602     }
603 
604     /**
605      * @hide
606      */
onWebViewProviderChanged(PackageInfo packageInfo)607     public static int onWebViewProviderChanged(PackageInfo packageInfo) {
608         int startedRelroProcesses = 0;
609         try {
610             startedRelroProcesses = WebViewLibraryLoader.prepareNativeLibraries(packageInfo);
611         } catch (Throwable t) {
612             // Log and discard errors at this stage as we must not crash the system server.
613             Slog.wtf(LOGTAG, "error preparing webview native library", t);
614         }
615 
616         WebViewZygote.onWebViewProviderChanged(packageInfo);
617 
618         return startedRelroProcesses;
619     }
620 
621     private static String WEBVIEW_UPDATE_SERVICE_NAME = "webviewupdate";
622 
623     /** @hide */
624     @UnsupportedAppUsage
getUpdateService()625     public static IWebViewUpdateService getUpdateService() {
626         if (isWebViewSupported()) {
627             return getUpdateServiceUnchecked();
628         } else {
629             return null;
630         }
631     }
632 
633     /** @hide */
getUpdateServiceUnchecked()634     static IWebViewUpdateService getUpdateServiceUnchecked() {
635         return IWebViewUpdateService.Stub.asInterface(
636                 ServiceManager.getService(WEBVIEW_UPDATE_SERVICE_NAME));
637     }
638 }
639