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