summaryrefslogtreecommitdiff
path: root/core/java/android/webkit
diff options
context:
space:
mode:
authorXin Li <delphij@google.com>2017-12-06 11:51:59 -0800
committerXin Li <delphij@google.com>2017-12-06 14:24:49 -0800
commit5364be50cd0431c3b323fd8a3725df5146d01e99 (patch)
tree379823ce960e903a2ba0313591c947ee2d595cf7 /core/java/android/webkit
parent8ab47567b2140da30257bc4e3b70495c8f17281e (diff)
parent592f539419226f5d8652c434b34885b93fda0f8d (diff)
DO NOT MERGE: Merge Oreo MR1 into master
Exempt-From-Owner-Approval: Changes already landed internally Change-Id: I727a014df2fb05a4b13cb67b1fcb760a8b387523
Diffstat (limited to 'core/java/android/webkit')
-rw-r--r--core/java/android/webkit/SafeBrowsingResponse.java52
-rw-r--r--core/java/android/webkit/UserPackage.java2
-rw-r--r--core/java/android/webkit/WebSettings.java12
-rw-r--r--core/java/android/webkit/WebView.java135
-rw-r--r--core/java/android/webkit/WebViewClient.java51
-rw-r--r--core/java/android/webkit/WebViewFactory.java265
-rw-r--r--core/java/android/webkit/WebViewFactoryProvider.java23
-rw-r--r--core/java/android/webkit/WebViewLibraryLoader.java320
8 files changed, 527 insertions, 333 deletions
diff --git a/core/java/android/webkit/SafeBrowsingResponse.java b/core/java/android/webkit/SafeBrowsingResponse.java
new file mode 100644
index 000000000000..0d0f1cce2dfc
--- /dev/null
+++ b/core/java/android/webkit/SafeBrowsingResponse.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.webkit;
+
+/**
+ * Used to indicate an action to take when hitting a malicious URL. Instances of this class are
+ * created by the WebView and passed to {@link android.webkit.WebViewClient#onSafeBrowsingHit}. The
+ * host application must call {@link #showInterstitial(boolean)}, {@link #proceed(boolean)}, or
+ * {@link #backToSafety(boolean)} to set the WebView's response to the Safe Browsing hit.
+ *
+ * <p>
+ * If reporting is enabled, all reports will be sent according to the privacy policy referenced by
+ * {@link android.webkit.WebView#getSafeBrowsingPrivacyPolicyUrl()}.
+ * </p>
+ */
+public abstract class SafeBrowsingResponse {
+
+ /**
+ * Display the default interstitial.
+ *
+ * @param allowReporting True if the interstitial should show a reporting checkbox.
+ */
+ public abstract void showInterstitial(boolean allowReporting);
+
+ /**
+ * Act as if the user clicked "visit this unsafe site."
+ *
+ * @param report True to enable Safe Browsing reporting.
+ */
+ public abstract void proceed(boolean report);
+
+ /**
+ * Act as if the user clicked "back to safety."
+ *
+ * @param report True to enable Safe Browsing reporting.
+ */
+ public abstract void backToSafety(boolean report);
+}
diff --git a/core/java/android/webkit/UserPackage.java b/core/java/android/webkit/UserPackage.java
index 892008948e87..9da64559d0fe 100644
--- a/core/java/android/webkit/UserPackage.java
+++ b/core/java/android/webkit/UserPackage.java
@@ -83,7 +83,7 @@ public class UserPackage {
* supported by the current framework version.
*/
public static boolean hasCorrectTargetSdkVersion(PackageInfo packageInfo) {
- return packageInfo.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.O;
+ return packageInfo.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.O_MR1;
}
public UserInfo getUserInfo() {
diff --git a/core/java/android/webkit/WebSettings.java b/core/java/android/webkit/WebSettings.java
index 3a6de9609b3c..82cff7c13e47 100644
--- a/core/java/android/webkit/WebSettings.java
+++ b/core/java/android/webkit/WebSettings.java
@@ -1390,17 +1390,15 @@ public abstract class WebSettings {
* Sets whether Safe Browsing is enabled. Safe browsing allows WebView to
* protect against malware and phishing attacks by verifying the links.
*
- * Safe browsing is disabled by default. The recommended way to enable
- * Safe browsing is using a manifest tag to change the default value to
- * enabled for all WebViews.
* <p>
- * <pre>
- * &lt;meta-data android:name="android.webkit.WebView.EnableSafeBrowsing"
- * android:value="true" /&gt;
- * </pre>
+ * Safe browsing is disabled by default. The recommended way to enable Safe browsing is using a
+ * manifest tag to change the default value to enabled for all WebViews (read <a
+ * href="{@docRoot}reference/android/webkit/WebView.html">general Safe Browsing info</a>).
* </p>
*
+ * <p>
* This API overrides the manifest tag value for this WebView.
+ * </p>
*
* @param enabled Whether Safe browsing is enabled.
*/
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index a0b4a0356233..637b60e2dcb4 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -67,6 +67,7 @@ import java.io.BufferedWriter;
import java.io.File;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.List;
import java.util.Map;
/**
@@ -318,6 +319,22 @@ import java.util.Map;
* out.
* </p>
*
+ * <h3>Safe Browsing</h3>
+ *
+ * <p>
+ * If Safe Browsing is enabled, WebView will block malicious URLs and present a warning UI to the
+ * user to allow them to navigate back safely or proceed to the malicious page.
+ * </p>
+ * <p>
+ * The recommended way for apps to enable the feature is putting the following tag in the manifest:
+ * </p>
+ * <p>
+ * <pre>
+ * &lt;meta-data android:name="android.webkit.WebView.EnableSafeBrowsing"
+ * android:value="true" /&gt;
+ * </pre>
+ * </p>
+ *
*/
// Implementation notes.
// The WebView is a thin API class that delegates its public API to a backend WebViewProvider
@@ -330,16 +347,6 @@ public class WebView extends AbsoluteLayout
implements ViewTreeObserver.OnGlobalFocusChangeListener,
ViewGroup.OnHierarchyChangeListener, ViewDebug.HierarchyHandler {
- /**
- * Broadcast Action: Indicates the data reduction proxy setting changed.
- * Sent by the settings app when user changes the data reduction proxy value. This intent will
- * always stay as a hidden API.
- * @hide
- */
- @SystemApi
- public static final String DATA_REDUCTION_PROXY_SETTING_CHANGED =
- "android.webkit.DATA_REDUCTION_PROXY_SETTING_CHANGED";
-
private static final String LOGTAG = "WebView";
// Throwing an exception for incorrect thread usage if the
@@ -1621,22 +1628,60 @@ public class WebView extends AbsoluteLayout
}
/**
- * Starts Safe Browsing initialization. This should only be called once.
- * @param context is the activity context the WebView will be used in.
- * @param callback will be called with the value true if initialization is
- * successful. The callback will be run on the UI thread.
- * @hide
+ * Starts Safe Browsing initialization.
+ * <p>
+ * URL loads are not guaranteed to be protected by Safe Browsing until after {@code callback} is
+ * invoked with {@code true}. Safe Browsing is not fully supported on all devices. For those
+ * devices {@code callback} will receive {@code false}.
+ * <p>
+ * This does not enable the Safe Browsing feature itself, and should only be called if Safe
+ * Browsing is enabled by the manifest tag or {@link WebSettings#setSafeBrowsingEnabled}. This
+ * prepares resources used for Safe Browsing.
+ * <p>
+ * This should be called with the Application Context (and will always use the Application
+ * context to do its work regardless).
+ *
+ * @param context Application Context.
+ * @param callback will be called on the UI thread with {@code true} if initialization is
+ * successful, {@code false} otherwise.
*/
- public static void initSafeBrowsing(Context context, ValueCallback<Boolean> callback) {
+ public static void startSafeBrowsing(Context context, ValueCallback<Boolean> callback) {
getFactory().getStatics().initSafeBrowsing(context, callback);
}
/**
- * Shuts down Safe Browsing. This should only be called once.
- * @hide
+ * Sets the list of domains that are exempt from SafeBrowsing checks. The list is
+ * global for all the WebViews.
+ * <p>
+ * Each rule should take one of these:
+ * <table>
+ * <tr><th> Rule </th> <th> Example </th> <th> Matches Subdomain</th> </tr>
+ * <tr><td> HOSTNAME </td> <td> example.com </td> <td> Yes </td> </tr>
+ * <tr><td> .HOSTNAME </td> <td> .example.com </td> <td> No </td> </tr>
+ * <tr><td> IPV4_LITERAL </td> <td> 192.168.1.1 </td> <td> No </td></tr>
+ * <tr><td> IPV6_LITERAL_WITH_BRACKETS </td><td>[10:20:30:40:50:60:70:80]</td><td>No</td></tr>
+ * </table>
+ * <p>
+ * All other rules, including wildcards, are invalid.
+ *
+ * @param urls the list of URLs
+ * @param callback will be called with true if URLs are successfully added to the whitelist.
+ * It will be called with false if any URLs are malformed. The callback will be run on
+ * the UI thread
*/
- public static void shutdownSafeBrowsing() {
- getFactory().getStatics().shutdownSafeBrowsing();
+ public static void setSafeBrowsingWhitelist(@NonNull List<String> urls,
+ @Nullable ValueCallback<Boolean> callback) {
+ getFactory().getStatics().setSafeBrowsingWhitelist(urls, callback);
+ }
+
+ /**
+ * Returns a URL pointing to the privacy policy for Safe Browsing reporting.
+ *
+ * @return the url pointing to a privacy policy document which can be displayed to users.
+ */
+ @NonNull
+ public static Uri getSafeBrowsingPrivacyPolicyUrl() {
+ return getFactory().getStatics().getSafeBrowsingPrivacyPolicyUrl();
}
/**
@@ -1880,13 +1925,14 @@ public class WebView extends AbsoluteLayout
* For applications targeted to API level {@link android.os.Build.VERSION_CODES#JELLY_BEAN} or below,
* all public methods (including the inherited ones) can be accessed, see the
* important security note below for implications.
- * <p> Note that injected objects will not
- * appear in JavaScript until the page is next (re)loaded. For example:
+ * <p> Note that injected objects will not appear in JavaScript until the page is next
+ * (re)loaded. JavaScript should be enabled before injecting the object. For example:
* <pre>
* class JsObject {
* {@literal @}JavascriptInterface
* public String toString() { return "injectedObject"; }
* }
+ * webview.getSettings().setJavaScriptEnabled(true);
* webView.addJavascriptInterface(new JsObject(), "injectedObject");
* webView.loadData("<!DOCTYPE html><title></title>", "text/html", null);
* webView.loadUrl("javascript:alert(injectedObject.toString())");</pre>
@@ -2274,7 +2320,6 @@ public class WebView extends AbsoluteLayout
/**
* Sets the {@link TextClassifier} for this WebView.
- * @hide
*/
public void setTextClassifier(@Nullable TextClassifier textClassifier) {
mProvider.setTextClassifier(textClassifier);
@@ -2283,7 +2328,6 @@ public class WebView extends AbsoluteLayout
/**
* Returns the {@link TextClassifier} used by this WebView.
* If no TextClassifier has been set, this WebView uses the default set by the system.
- * @hide
*/
@NonNull
public TextClassifier getTextClassifier() {
@@ -2679,25 +2723,20 @@ public class WebView extends AbsoluteLayout
* {@code IFRAME}, in which case it would be treated the same way as multiple forms described
* above, except that the {@link ViewStructure#setWebDomain(String) web domain} of the
* {@code FORM} contains the {@code src} attribute from the {@code IFRAME} node.
- * <li>If the Android SDK provides a similar View, then should be set with the
- * fully-qualified class name of such view.
* <li>The W3C autofill field ({@code autocomplete} tag attribute) maps to
- * {@link ViewStructure#setAutofillHints(String[])}.
- * <li>The {@code type} attribute of {@code INPUT} tags maps to
- * {@link ViewStructure#setInputType(int)}.
- * <li>The {@code value} attribute of {@code INPUT} tags maps to
- * {@link ViewStructure#setText(CharSequence)}.
- * <li>If the view is editalbe, the {@link ViewStructure#setAutofillType(int)} and
+ * {@link ViewStructure#setAutofillHints(String[])}.
+ * <li>If the view is editable, the {@link ViewStructure#setAutofillType(int)} and
* {@link ViewStructure#setAutofillValue(AutofillValue)} must be set.
* <li>The {@code placeholder} attribute maps to {@link ViewStructure#setHint(CharSequence)}.
* <li>Other HTML attributes can be represented through
* {@link ViewStructure#setHtmlInfo(android.view.ViewStructure.HtmlInfo)}.
* </ol>
*
- * <p>It should also call {@code structure.setDataIsSensitive(false)} for fields whose value
- * were not dynamically changed (for example, through Javascript).
+ * <p>If the WebView implementation can determine that the value of a field was set statically
+ * (for example, not through Javascript), it should also call
+ * {@code structure.setDataIsSensitive(false)}.
*
- * <p>Example1: an HTML form with 2 fields for username and password.
+ * <p>For example, an HTML form with 2 fields for username and password:
*
* <pre class="prettyprint">
* &lt;input type="text" name="username" id="user" value="Type your username" autocomplete="username" placeholder="Email or username"&gt;
@@ -2710,51 +2749,27 @@ public class WebView extends AbsoluteLayout
* int index = structure.addChildCount(2);
* ViewStructure username = structure.newChild(index);
* username.setAutofillId(structure.getAutofillId(), 1); // id 1 - first child
- * username.setClassName("input");
- * username.setInputType("android.widget.EditText");
* username.setAutofillHints("username");
* username.setHtmlInfo(username.newHtmlInfoBuilder("input")
* .addAttribute("type", "text")
* .addAttribute("name", "username")
- * .addAttribute("id", "user")
* .build());
* username.setHint("Email or username");
* username.setAutofillType(View.AUTOFILL_TYPE_TEXT);
* username.setAutofillValue(AutofillValue.forText("Type your username"));
- * username.setText("Type your username");
- * // Value of the field is not sensitive because it was not dynamically changed:
+ * // Value of the field is not sensitive because it was created statically and not changed.
* username.setDataIsSensitive(false);
*
* ViewStructure password = structure.newChild(index + 1);
* username.setAutofillId(structure, 2); // id 2 - second child
- * password.setInputType("android.widget.EditText");
- * password.setInputType(InputType.TYPE_TEXT_VARIATION_PASSWORD);
* password.setAutofillHints("current-password");
* password.setHtmlInfo(password.newHtmlInfoBuilder("input")
* .addAttribute("type", "password")
* .addAttribute("name", "password")
- * .addAttribute("id", "pass")
* .build());
* password.setHint("Password");
* password.setAutofillType(View.AUTOFILL_TYPE_TEXT);
* </pre>
- *
- * <p>Example2: an IFRAME tag.
- *
- * <pre class="prettyprint">
- * &lt;iframe src="https://example.com/login"/&gt;
- * </pre>
- *
- * <p>Would map to:
- *
- * <pre class="prettyprint">
- * int index = structure.addChildCount(1);
- * ViewStructure iframe = structure.newChildFor(index);
- * iframe.setAutofillId(structure.getAutofillId(), 1);
- * iframe.setHtmlInfo(iframe.newHtmlInfoBuilder("iframe")
- * .addAttribute("src", "https://example.com/login")
- * .build());
- * </pre>
*/
@Override
public void onProvideAutofillVirtualStructure(ViewStructure structure, int flags) {
diff --git a/core/java/android/webkit/WebViewClient.java b/core/java/android/webkit/WebViewClient.java
index 788908ad9468..cbe75c405fe4 100644
--- a/core/java/android/webkit/WebViewClient.java
+++ b/core/java/android/webkit/WebViewClient.java
@@ -16,6 +16,7 @@
package android.webkit;
+import android.annotation.IntDef;
import android.graphics.Bitmap;
import android.net.http.SslError;
import android.os.Message;
@@ -23,6 +24,9 @@ import android.view.InputEvent;
import android.view.KeyEvent;
import android.view.ViewRootImpl;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
public class WebViewClient {
/**
@@ -150,6 +154,10 @@ public class WebViewClient {
* other than the UI thread so clients should exercise caution
* when accessing private data or the view system.
*
+ * <p>Note: when Safe Browsing is enabled, these URLs still undergo Safe Browsing checks. If
+ * this is undesired, whitelist the URL with {@link WebView#setSafeBrowsingWhitelist} or ignore
+ * the warning with {@link #onSafeBrowsingHit}.
+ *
* @param view The {@link android.webkit.WebView} that is requesting the
* resource.
* @param url The raw url of the resource.
@@ -173,6 +181,10 @@ public class WebViewClient {
* other than the UI thread so clients should exercise caution
* when accessing private data or the view system.
*
+ * <p>Note: when Safe Browsing is enabled, these URLs still undergo Safe Browsing checks. If
+ * this is undesired, whitelist the URL with {@link WebView#setSafeBrowsingWhitelist} or ignore
+ * the warning with {@link #onSafeBrowsingHit}.
+ *
* @param view The {@link android.webkit.WebView} that is requesting the
* resource.
* @param request Object containing the details of the request.
@@ -237,6 +249,25 @@ public class WebViewClient {
/** Resource load was cancelled by Safe Browsing */
public static final int ERROR_UNSAFE_RESOURCE = -16;
+ /** @hide */
+ @IntDef({
+ SAFE_BROWSING_THREAT_UNKNOWN,
+ SAFE_BROWSING_THREAT_MALWARE,
+ SAFE_BROWSING_THREAT_PHISHING,
+ SAFE_BROWSING_THREAT_UNWANTED_SOFTWARE
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface SafeBrowsingThreat {}
+
+ /** The resource was blocked for an unknown reason */
+ public static final int SAFE_BROWSING_THREAT_UNKNOWN = 0;
+ /** The resource was blocked because it contains malware */
+ public static final int SAFE_BROWSING_THREAT_MALWARE = 1;
+ /** The resource was blocked because it contains deceptive content */
+ public static final int SAFE_BROWSING_THREAT_PHISHING = 2;
+ /** The resource was blocked because it contains unwanted software */
+ public static final int SAFE_BROWSING_THREAT_UNWANTED_SOFTWARE = 3;
+
/**
* Report an error to the host application. These errors are unrecoverable
* (i.e. the main resource is unavailable). The errorCode parameter
@@ -496,4 +527,24 @@ public class WebViewClient {
public boolean onRenderProcessGone(WebView view, RenderProcessGoneDetail detail) {
return false;
}
+
+ /**
+ * Notify the host application that a loading URL has been flagged by Safe Browsing.
+ *
+ * The application must invoke the callback to indicate the preferred response. The default
+ * behavior is to show an interstitial to the user, with the reporting checkbox visible.
+ *
+ * If the application needs to show its own custom interstitial UI, the callback can be invoked
+ * asynchronously with backToSafety() or proceed(), depending on user response.
+ *
+ * @param view The WebView that hit the malicious resource.
+ * @param request Object containing the details of the request.
+ * @param threatType The reason the resource was caught by Safe Browsing, corresponding to a
+ * SAFE_BROWSING_THREAT_* value.
+ * @param callback Applications must invoke one of the callback methods.
+ */
+ public void onSafeBrowsingHit(WebView view, WebResourceRequest request,
+ @SafeBrowsingThreat int threatType, SafeBrowsingResponse callback) {
+ callback.showInterstitial(/* allowReporting */ true);
+ }
}
diff --git a/core/java/android/webkit/WebViewFactory.java b/core/java/android/webkit/WebViewFactory.java
index 1b6b3923d130..668cfba94071 100644
--- a/core/java/android/webkit/WebViewFactory.java
+++ b/core/java/android/webkit/WebViewFactory.java
@@ -18,7 +18,6 @@ package android.webkit;
import android.annotation.SystemApi;
import android.app.ActivityManager;
-import android.app.ActivityManagerInternal;
import android.app.AppGlobals;
import android.app.Application;
import android.content.Context;
@@ -27,27 +26,15 @@ import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.Signature;
import android.os.Build;
-import android.os.Process;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.StrictMode;
-import android.os.SystemProperties;
import android.os.Trace;
-import android.text.TextUtils;
import android.util.AndroidRuntimeException;
import android.util.ArraySet;
import android.util.Log;
-import com.android.server.LocalServices;
-
-import dalvik.system.VMRuntime;
-
import java.lang.reflect.Method;
-import java.io.File;
-import java.io.IOException;
-import java.util.Arrays;
-import java.util.zip.ZipEntry;
-import java.util.zip.ZipFile;
/**
* Top level factory, used creating all the main WebView implementation classes.
@@ -60,21 +47,15 @@ public final class WebViewFactory {
// visible for WebViewZygoteInit to look up the class by reflection and call preloadInZygote.
/** @hide */
private static final String CHROMIUM_WEBVIEW_FACTORY =
- "com.android.webview.chromium.WebViewChromiumFactoryProviderForO";
+ "com.android.webview.chromium.WebViewChromiumFactoryProviderForOMR1";
private static final String CHROMIUM_WEBVIEW_FACTORY_METHOD = "create";
private static final String NULL_WEBVIEW_FACTORY =
"com.android.webview.nullwebview.NullWebViewFactoryProvider";
- private static final String CHROMIUM_WEBVIEW_NATIVE_RELRO_32 =
- "/data/misc/shared_relro/libwebviewchromium32.relro";
- private static final String CHROMIUM_WEBVIEW_NATIVE_RELRO_64 =
- "/data/misc/shared_relro/libwebviewchromium64.relro";
-
public static final String CHROMIUM_WEBVIEW_VMSIZE_SIZE_PROPERTY =
"persist.sys.webview.vmsize";
- private static final long CHROMIUM_WEBVIEW_DEFAULT_VMSIZE_BYTES = 100 * 1024 * 1024;
private static final String LOGTAG = "WebViewFactory";
@@ -84,7 +65,6 @@ public final class WebViewFactory {
// same provider.
private static WebViewFactoryProvider sProviderInstance;
private static final Object sProviderLock = new Object();
- private static boolean sAddressSpaceReserved = false;
private static PackageInfo sPackageInfo;
// Error codes for loadWebViewNativeLibraryFromPackage
@@ -120,7 +100,7 @@ public final class WebViewFactory {
return "Unknown";
}
- private static class MissingWebViewPackageException extends Exception {
+ static class MissingWebViewPackageException extends Exception {
public MissingWebViewPackageException(String message) { super(message); }
public MissingWebViewPackageException(Exception e) { super(e); }
}
@@ -183,7 +163,7 @@ public final class WebViewFactory {
}
try {
- int loadNativeRet = loadNativeLibrary(clazzLoader, packageInfo);
+ int loadNativeRet = WebViewLibraryLoader.loadNativeLibrary(clazzLoader, packageInfo);
// If we failed waiting for relro we want to return that fact even if we successfully
// load the relro file.
if (loadNativeRet == LIBLOAD_SUCCESS) return response.status;
@@ -414,7 +394,7 @@ public final class WebViewFactory {
ClassLoader clazzLoader = webViewContext.getClassLoader();
Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "WebViewFactory.loadNativeLibrary()");
- loadNativeLibrary(clazzLoader, sPackageInfo);
+ WebViewLibraryLoader.loadNativeLibrary(clazzLoader, sPackageInfo);
Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW);
Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "Class.forName()");
@@ -450,20 +430,7 @@ public final class WebViewFactory {
*/
public static void prepareWebViewInZygote() {
try {
- System.loadLibrary("webviewchromium_loader");
- long addressSpaceToReserve =
- SystemProperties.getLong(CHROMIUM_WEBVIEW_VMSIZE_SIZE_PROPERTY,
- CHROMIUM_WEBVIEW_DEFAULT_VMSIZE_BYTES);
- sAddressSpaceReserved = nativeReserveAddressSpace(addressSpaceToReserve);
-
- if (sAddressSpaceReserved) {
- if (DEBUG) {
- Log.v(LOGTAG, "address space reserved: " + addressSpaceToReserve + " bytes");
- }
- } else {
- Log.e(LOGTAG, "reserving " + addressSpaceToReserve +
- " bytes of address space failed");
- }
+ WebViewLibraryLoader.reserveAddressSpaceInZygote();
} catch (Throwable t) {
// Log and discard errors at this stage as we must not crash the zygote.
Log.e(LOGTAG, "error preparing native loader", t);
@@ -479,13 +446,13 @@ public final class WebViewFactory {
// waiting on relro creation.
if (Build.SUPPORTED_32_BIT_ABIS.length > 0) {
if (DEBUG) Log.v(LOGTAG, "Create 32 bit relro");
- createRelroFile(false /* is64Bit */, nativeLibraryPaths);
+ WebViewLibraryLoader.createRelroFile(false /* is64Bit */, nativeLibraryPaths);
numRelros++;
}
if (Build.SUPPORTED_64_BIT_ABIS.length > 0) {
if (DEBUG) Log.v(LOGTAG, "Create 64 bit relro");
- createRelroFile(true /* is64Bit */, nativeLibraryPaths);
+ WebViewLibraryLoader.createRelroFile(true /* is64Bit */, nativeLibraryPaths);
numRelros++;
}
return numRelros;
@@ -501,49 +468,7 @@ public final class WebViewFactory {
fixupStubApplicationInfo(packageInfo.applicationInfo,
AppGlobals.getInitialApplication().getPackageManager());
- nativeLibs = WebViewFactory.getWebViewNativeLibraryPaths(packageInfo);
- if (nativeLibs != null) {
- long newVmSize = 0L;
-
- for (String path : nativeLibs) {
- if (path == null || TextUtils.isEmpty(path)) continue;
- if (DEBUG) Log.d(LOGTAG, "Checking file size of " + path);
- File f = new File(path);
- if (f.exists()) {
- newVmSize = Math.max(newVmSize, f.length());
- continue;
- }
- if (path.contains("!/")) {
- String[] split = TextUtils.split(path, "!/");
- if (split.length == 2) {
- try (ZipFile z = new ZipFile(split[0])) {
- ZipEntry e = z.getEntry(split[1]);
- if (e != null && e.getMethod() == ZipEntry.STORED) {
- newVmSize = Math.max(newVmSize, e.getSize());
- continue;
- }
- }
- catch (IOException e) {
- Log.e(LOGTAG, "error reading APK file " + split[0] + ", ", e);
- }
- }
- }
- Log.e(LOGTAG, "error sizing load for " + path);
- }
-
- if (DEBUG) {
- Log.v(LOGTAG, "Based on library size, need " + newVmSize +
- " bytes of address space.");
- }
- // The required memory can be larger than the file on disk (due to .bss), and an
- // upgraded version of the library will likely be larger, so always attempt to
- // reserve twice as much as we think to allow for the library to grow during this
- // boot cycle.
- newVmSize = Math.max(2 * newVmSize, CHROMIUM_WEBVIEW_DEFAULT_VMSIZE_BYTES);
- Log.d(LOGTAG, "Setting new address space to " + newVmSize);
- SystemProperties.set(CHROMIUM_WEBVIEW_VMSIZE_SIZE_PROPERTY,
- Long.toString(newVmSize));
- }
+ nativeLibs = WebViewLibraryLoader.updateWebViewZygoteVmSize(packageInfo);
} catch (Throwable t) {
// Log and discard errors at this stage as we must not crash the system server.
Log.e(LOGTAG, "error preparing webview native library", t);
@@ -554,173 +479,6 @@ public final class WebViewFactory {
return prepareWebViewInSystemServer(nativeLibs);
}
- private static String getLoadFromApkPath(String apkPath,
- String[] abiList,
- String nativeLibFileName)
- throws MissingWebViewPackageException {
- // Search the APK for a native library conforming to a listed ABI.
- try (ZipFile z = new ZipFile(apkPath)) {
- for (String abi : abiList) {
- final String entry = "lib/" + abi + "/" + nativeLibFileName;
- ZipEntry e = z.getEntry(entry);
- if (e != null && e.getMethod() == ZipEntry.STORED) {
- // Return a path formatted for dlopen() load from APK.
- return apkPath + "!/" + entry;
- }
- }
- } catch (IOException e) {
- throw new MissingWebViewPackageException(e);
- }
- return "";
- }
-
- private static String[] getWebViewNativeLibraryPaths(PackageInfo packageInfo)
- throws MissingWebViewPackageException {
- ApplicationInfo ai = packageInfo.applicationInfo;
- final String NATIVE_LIB_FILE_NAME = getWebViewLibrary(ai);
-
- String path32;
- String path64;
- boolean primaryArchIs64bit = VMRuntime.is64BitAbi(ai.primaryCpuAbi);
- if (!TextUtils.isEmpty(ai.secondaryCpuAbi)) {
- // Multi-arch case.
- if (primaryArchIs64bit) {
- // Primary arch: 64-bit, secondary: 32-bit.
- path64 = ai.nativeLibraryDir;
- path32 = ai.secondaryNativeLibraryDir;
- } else {
- // Primary arch: 32-bit, secondary: 64-bit.
- path64 = ai.secondaryNativeLibraryDir;
- path32 = ai.nativeLibraryDir;
- }
- } else if (primaryArchIs64bit) {
- // Single-arch 64-bit.
- path64 = ai.nativeLibraryDir;
- path32 = "";
- } else {
- // Single-arch 32-bit.
- path32 = ai.nativeLibraryDir;
- path64 = "";
- }
-
- // Form the full paths to the extracted native libraries.
- // If libraries were not extracted, try load from APK paths instead.
- if (!TextUtils.isEmpty(path32)) {
- path32 += "/" + NATIVE_LIB_FILE_NAME;
- File f = new File(path32);
- if (!f.exists()) {
- path32 = getLoadFromApkPath(ai.sourceDir,
- Build.SUPPORTED_32_BIT_ABIS,
- NATIVE_LIB_FILE_NAME);
- }
- }
- if (!TextUtils.isEmpty(path64)) {
- path64 += "/" + NATIVE_LIB_FILE_NAME;
- File f = new File(path64);
- if (!f.exists()) {
- path64 = getLoadFromApkPath(ai.sourceDir,
- Build.SUPPORTED_64_BIT_ABIS,
- NATIVE_LIB_FILE_NAME);
- }
- }
-
- if (DEBUG) Log.v(LOGTAG, "Native 32-bit lib: " + path32 + ", 64-bit lib: " + path64);
- return new String[] { path32, path64 };
- }
-
- private static void createRelroFile(final boolean is64Bit, String[] nativeLibraryPaths) {
- final String abi =
- is64Bit ? Build.SUPPORTED_64_BIT_ABIS[0] : Build.SUPPORTED_32_BIT_ABIS[0];
-
- // crashHandler is invoked by the ActivityManagerService when the isolated process crashes.
- Runnable crashHandler = new Runnable() {
- @Override
- public void run() {
- try {
- Log.e(LOGTAG, "relro file creator for " + abi + " crashed. Proceeding without");
- getUpdateService().notifyRelroCreationCompleted();
- } catch (RemoteException e) {
- Log.e(LOGTAG, "Cannot reach WebViewUpdateService. " + e.getMessage());
- }
- }
- };
-
- try {
- if (nativeLibraryPaths == null
- || nativeLibraryPaths[0] == null || nativeLibraryPaths[1] == null) {
- throw new IllegalArgumentException(
- "Native library paths to the WebView RelRo process must not be null!");
- }
- int pid = LocalServices.getService(ActivityManagerInternal.class).startIsolatedProcess(
- RelroFileCreator.class.getName(), nativeLibraryPaths, "WebViewLoader-" + abi, abi,
- Process.SHARED_RELRO_UID, crashHandler);
- if (pid <= 0) throw new Exception("Failed to start the relro file creator process");
- } catch (Throwable t) {
- // Log and discard errors as we must not crash the system server.
- Log.e(LOGTAG, "error starting relro file creator for abi " + abi, t);
- crashHandler.run();
- }
- }
-
- private static class RelroFileCreator {
- // Called in an unprivileged child process to create the relro file.
- public static void main(String[] args) {
- boolean result = false;
- boolean is64Bit = VMRuntime.getRuntime().is64Bit();
- try{
- if (args.length != 2 || args[0] == null || args[1] == null) {
- Log.e(LOGTAG, "Invalid RelroFileCreator args: " + Arrays.toString(args));
- return;
- }
- Log.v(LOGTAG, "RelroFileCreator (64bit = " + is64Bit + "), " +
- " 32-bit lib: " + args[0] + ", 64-bit lib: " + args[1]);
- if (!sAddressSpaceReserved) {
- Log.e(LOGTAG, "can't create relro file; address space not reserved");
- return;
- }
- result = nativeCreateRelroFile(args[0] /* path32 */,
- args[1] /* path64 */,
- CHROMIUM_WEBVIEW_NATIVE_RELRO_32,
- CHROMIUM_WEBVIEW_NATIVE_RELRO_64);
- if (result && DEBUG) Log.v(LOGTAG, "created relro file");
- } finally {
- // We must do our best to always notify the update service, even if something fails.
- try {
- getUpdateService().notifyRelroCreationCompleted();
- } catch (RemoteException e) {
- Log.e(LOGTAG, "error notifying update service", e);
- }
-
- if (!result) Log.e(LOGTAG, "failed to create relro file");
-
- // Must explicitly exit or else this process will just sit around after we return.
- System.exit(0);
- }
- }
- }
-
- // Assumes that we have waited for relro creation
- private static int loadNativeLibrary(ClassLoader clazzLoader, PackageInfo packageInfo)
- throws MissingWebViewPackageException {
- if (!sAddressSpaceReserved) {
- Log.e(LOGTAG, "can't load with relro file; address space not reserved");
- return LIBLOAD_ADDRESS_SPACE_NOT_RESERVED;
- }
-
- String[] args = getWebViewNativeLibraryPaths(packageInfo);
- int result = nativeLoadWithRelroFile(args[0] /* path32 */,
- args[1] /* path64 */,
- CHROMIUM_WEBVIEW_NATIVE_RELRO_32,
- CHROMIUM_WEBVIEW_NATIVE_RELRO_64,
- clazzLoader);
- if (result != LIBLOAD_SUCCESS) {
- Log.w(LOGTAG, "failed to load with relro file, proceeding without");
- } else if (DEBUG) {
- Log.v(LOGTAG, "loaded with relro file");
- }
- return result;
- }
-
private static String WEBVIEW_UPDATE_SERVICE_NAME = "webviewupdate";
/** @hide */
@@ -728,11 +486,4 @@ public final class WebViewFactory {
return IWebViewUpdateService.Stub.asInterface(
ServiceManager.getService(WEBVIEW_UPDATE_SERVICE_NAME));
}
-
- private static native boolean nativeReserveAddressSpace(long addressSpaceToReserve);
- private static native boolean nativeCreateRelroFile(String lib32, String lib64,
- String relro32, String relro64);
- private static native int nativeLoadWithRelroFile(String lib32, String lib64,
- String relro32, String relro64,
- ClassLoader clazzLoader);
}
diff --git a/core/java/android/webkit/WebViewFactoryProvider.java b/core/java/android/webkit/WebViewFactoryProvider.java
index 00fdac89d028..4c47abc65a65 100644
--- a/core/java/android/webkit/WebViewFactoryProvider.java
+++ b/core/java/android/webkit/WebViewFactoryProvider.java
@@ -16,11 +16,14 @@
package android.webkit;
+import android.annotation.NonNull;
import android.annotation.SystemApi;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
+import java.util.List;
+
/**
* This is the main entry-point into the WebView back end implementations, which the WebView
* proxy class uses to instantiate all the other objects as needed. The backend must provide an
@@ -77,19 +80,23 @@ public interface WebViewFactoryProvider {
/**
* Implement the API method
- * {@link android.webkit.WebView#initSafeBrowsing(Context , ValueCallback<Boolean>)}
- * @hide
+ * {@link android.webkit.WebView#startSafeBrowsing(Context , ValueCallback<Boolean>)}
*/
- default void initSafeBrowsing(Context context, ValueCallback<Boolean> callback) {
- }
+ void initSafeBrowsing(Context context, ValueCallback<Boolean> callback);
+
+ /**
+ * Implement the API method
+ * {@link android.webkit.WebView#setSafeBrowsingWhitelist(List<String>,
+ * ValueCallback<Boolean>)}
+ */
+ void setSafeBrowsingWhitelist(List<String> urls, ValueCallback<Boolean> callback);
/**
* Implement the API method
- * {@link android.webkit.WebView#shutdownSafeBrowsing()}
- * @hide
+ * {@link android.webkit.WebView#getSafeBrowsingPrivacyPolicyUrl()}
*/
- default void shutdownSafeBrowsing() {
- }
+ @NonNull
+ Uri getSafeBrowsingPrivacyPolicyUrl();
}
Statics getStatics();
diff --git a/core/java/android/webkit/WebViewLibraryLoader.java b/core/java/android/webkit/WebViewLibraryLoader.java
new file mode 100644
index 000000000000..6f9e8ece4b13
--- /dev/null
+++ b/core/java/android/webkit/WebViewLibraryLoader.java
@@ -0,0 +1,320 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.webkit;
+
+import android.app.ActivityManagerInternal;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.os.Build;
+import android.os.Process;
+import android.os.RemoteException;
+import android.os.SystemProperties;
+import android.text.TextUtils;
+import android.util.Log;
+
+import com.android.server.LocalServices;
+
+import dalvik.system.VMRuntime;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+
+class WebViewLibraryLoader {
+ private static final String LOGTAG = WebViewLibraryLoader.class.getSimpleName();
+
+ private static final String CHROMIUM_WEBVIEW_NATIVE_RELRO_32 =
+ "/data/misc/shared_relro/libwebviewchromium32.relro";
+ private static final String CHROMIUM_WEBVIEW_NATIVE_RELRO_64 =
+ "/data/misc/shared_relro/libwebviewchromium64.relro";
+ private static final long CHROMIUM_WEBVIEW_DEFAULT_VMSIZE_BYTES = 100 * 1024 * 1024;
+
+ private static final boolean DEBUG = false;
+
+ private static boolean sAddressSpaceReserved = false;
+
+ /**
+ * Private class for running the actual relro creation in an unprivileged child process.
+ * RelroFileCreator is a static class (without access to the outer class) to avoid accidentally
+ * using any static members from the outer class. Those members will in reality differ between
+ * the child process in which RelroFileCreator operates, and the app process in which the static
+ * members of this class are used.
+ */
+ private static class RelroFileCreator {
+ // Called in an unprivileged child process to create the relro file.
+ public static void main(String[] args) {
+ boolean result = false;
+ boolean is64Bit = VMRuntime.getRuntime().is64Bit();
+ try {
+ if (args.length != 2 || args[0] == null || args[1] == null) {
+ Log.e(LOGTAG, "Invalid RelroFileCreator args: " + Arrays.toString(args));
+ return;
+ }
+ Log.v(LOGTAG, "RelroFileCreator (64bit = " + is64Bit + "), "
+ + " 32-bit lib: " + args[0] + ", 64-bit lib: " + args[1]);
+ if (!sAddressSpaceReserved) {
+ Log.e(LOGTAG, "can't create relro file; address space not reserved");
+ return;
+ }
+ result = nativeCreateRelroFile(args[0] /* path32 */,
+ args[1] /* path64 */,
+ CHROMIUM_WEBVIEW_NATIVE_RELRO_32,
+ CHROMIUM_WEBVIEW_NATIVE_RELRO_64);
+ if (result && DEBUG) Log.v(LOGTAG, "created relro file");
+ } finally {
+ // We must do our best to always notify the update service, even if something fails.
+ try {
+ WebViewFactory.getUpdateService().notifyRelroCreationCompleted();
+ } catch (RemoteException e) {
+ Log.e(LOGTAG, "error notifying update service", e);
+ }
+
+ if (!result) Log.e(LOGTAG, "failed to create relro file");
+
+ // Must explicitly exit or else this process will just sit around after we return.
+ System.exit(0);
+ }
+ }
+ }
+
+ /**
+ * Create a single relro file by invoking an isolated process that to do the actual work.
+ */
+ static void createRelroFile(final boolean is64Bit, String[] nativeLibraryPaths) {
+ final String abi =
+ is64Bit ? Build.SUPPORTED_64_BIT_ABIS[0] : Build.SUPPORTED_32_BIT_ABIS[0];
+
+ // crashHandler is invoked by the ActivityManagerService when the isolated process crashes.
+ Runnable crashHandler = new Runnable() {
+ @Override
+ public void run() {
+ try {
+ Log.e(LOGTAG, "relro file creator for " + abi + " crashed. Proceeding without");
+ WebViewFactory.getUpdateService().notifyRelroCreationCompleted();
+ } catch (RemoteException e) {
+ Log.e(LOGTAG, "Cannot reach WebViewUpdateService. " + e.getMessage());
+ }
+ }
+ };
+
+ try {
+ if (nativeLibraryPaths == null
+ || nativeLibraryPaths[0] == null || nativeLibraryPaths[1] == null) {
+ throw new IllegalArgumentException(
+ "Native library paths to the WebView RelRo process must not be null!");
+ }
+ int pid = LocalServices.getService(ActivityManagerInternal.class).startIsolatedProcess(
+ RelroFileCreator.class.getName(), nativeLibraryPaths,
+ "WebViewLoader-" + abi, abi, Process.SHARED_RELRO_UID, crashHandler);
+ if (pid <= 0) throw new Exception("Failed to start the relro file creator process");
+ } catch (Throwable t) {
+ // Log and discard errors as we must not crash the system server.
+ Log.e(LOGTAG, "error starting relro file creator for abi " + abi, t);
+ crashHandler.run();
+ }
+ }
+
+ /**
+ *
+ * @return the native WebView libraries in the new WebView APK.
+ */
+ static String[] updateWebViewZygoteVmSize(PackageInfo packageInfo)
+ throws WebViewFactory.MissingWebViewPackageException {
+ // Find the native libraries of the new WebView package, to change the size of the
+ // memory region in the Zygote reserved for the library.
+ String[] nativeLibs = getWebViewNativeLibraryPaths(packageInfo);
+ if (nativeLibs != null) {
+ long newVmSize = 0L;
+
+ for (String path : nativeLibs) {
+ if (path == null || TextUtils.isEmpty(path)) continue;
+ if (DEBUG) Log.d(LOGTAG, "Checking file size of " + path);
+ File f = new File(path);
+ if (f.exists()) {
+ newVmSize = Math.max(newVmSize, f.length());
+ continue;
+ }
+ if (path.contains("!/")) {
+ String[] split = TextUtils.split(path, "!/");
+ if (split.length == 2) {
+ try (ZipFile z = new ZipFile(split[0])) {
+ ZipEntry e = z.getEntry(split[1]);
+ if (e != null && e.getMethod() == ZipEntry.STORED) {
+ newVmSize = Math.max(newVmSize, e.getSize());
+ continue;
+ }
+ }
+ catch (IOException e) {
+ Log.e(LOGTAG, "error reading APK file " + split[0] + ", ", e);
+ }
+ }
+ }
+ Log.e(LOGTAG, "error sizing load for " + path);
+ }
+
+ if (DEBUG) {
+ Log.v(LOGTAG, "Based on library size, need " + newVmSize
+ + " bytes of address space.");
+ }
+ // The required memory can be larger than the file on disk (due to .bss), and an
+ // upgraded version of the library will likely be larger, so always attempt to
+ // reserve twice as much as we think to allow for the library to grow during this
+ // boot cycle.
+ newVmSize = Math.max(2 * newVmSize, CHROMIUM_WEBVIEW_DEFAULT_VMSIZE_BYTES);
+ Log.d(LOGTAG, "Setting new address space to " + newVmSize);
+ setWebViewZygoteVmSize(newVmSize);
+ }
+ return nativeLibs;
+ }
+
+ /**
+ * Reserve space for the native library to be loaded into.
+ */
+ static void reserveAddressSpaceInZygote() {
+ System.loadLibrary("webviewchromium_loader");
+ long addressSpaceToReserve =
+ SystemProperties.getLong(WebViewFactory.CHROMIUM_WEBVIEW_VMSIZE_SIZE_PROPERTY,
+ CHROMIUM_WEBVIEW_DEFAULT_VMSIZE_BYTES);
+ sAddressSpaceReserved = nativeReserveAddressSpace(addressSpaceToReserve);
+
+ if (sAddressSpaceReserved) {
+ if (DEBUG) {
+ Log.v(LOGTAG, "address space reserved: " + addressSpaceToReserve + " bytes");
+ }
+ } else {
+ Log.e(LOGTAG, "reserving " + addressSpaceToReserve + " bytes of address space failed");
+ }
+ }
+
+ /**
+ * Load WebView's native library into the current process.
+ * Note: assumes that we have waited for relro creation.
+ * @param clazzLoader class loader used to find the linker namespace to load the library into.
+ * @param packageInfo the package from which WebView is loaded.
+ */
+ static int loadNativeLibrary(ClassLoader clazzLoader, PackageInfo packageInfo)
+ throws WebViewFactory.MissingWebViewPackageException {
+ if (!sAddressSpaceReserved) {
+ Log.e(LOGTAG, "can't load with relro file; address space not reserved");
+ return WebViewFactory.LIBLOAD_ADDRESS_SPACE_NOT_RESERVED;
+ }
+
+ final String libraryFileName =
+ WebViewFactory.getWebViewLibrary(packageInfo.applicationInfo);
+ int result = nativeLoadWithRelroFile(libraryFileName, CHROMIUM_WEBVIEW_NATIVE_RELRO_32,
+ CHROMIUM_WEBVIEW_NATIVE_RELRO_64, clazzLoader);
+ if (result != WebViewFactory.LIBLOAD_SUCCESS) {
+ Log.w(LOGTAG, "failed to load with relro file, proceeding without");
+ } else if (DEBUG) {
+ Log.v(LOGTAG, "loaded with relro file");
+ }
+ return result;
+ }
+
+ /**
+ * Fetch WebView's native library paths from {@param packageInfo}.
+ */
+ static String[] getWebViewNativeLibraryPaths(PackageInfo packageInfo)
+ throws WebViewFactory.MissingWebViewPackageException {
+ ApplicationInfo ai = packageInfo.applicationInfo;
+ final String nativeLibFileName = WebViewFactory.getWebViewLibrary(ai);
+
+ String path32;
+ String path64;
+ boolean primaryArchIs64bit = VMRuntime.is64BitAbi(ai.primaryCpuAbi);
+ if (!TextUtils.isEmpty(ai.secondaryCpuAbi)) {
+ // Multi-arch case.
+ if (primaryArchIs64bit) {
+ // Primary arch: 64-bit, secondary: 32-bit.
+ path64 = ai.nativeLibraryDir;
+ path32 = ai.secondaryNativeLibraryDir;
+ } else {
+ // Primary arch: 32-bit, secondary: 64-bit.
+ path64 = ai.secondaryNativeLibraryDir;
+ path32 = ai.nativeLibraryDir;
+ }
+ } else if (primaryArchIs64bit) {
+ // Single-arch 64-bit.
+ path64 = ai.nativeLibraryDir;
+ path32 = "";
+ } else {
+ // Single-arch 32-bit.
+ path32 = ai.nativeLibraryDir;
+ path64 = "";
+ }
+
+ // Form the full paths to the extracted native libraries.
+ // If libraries were not extracted, try load from APK paths instead.
+ if (!TextUtils.isEmpty(path32)) {
+ path32 += "/" + nativeLibFileName;
+ File f = new File(path32);
+ if (!f.exists()) {
+ path32 = getLoadFromApkPath(ai.sourceDir,
+ Build.SUPPORTED_32_BIT_ABIS,
+ nativeLibFileName);
+ }
+ }
+ if (!TextUtils.isEmpty(path64)) {
+ path64 += "/" + nativeLibFileName;
+ File f = new File(path64);
+ if (!f.exists()) {
+ path64 = getLoadFromApkPath(ai.sourceDir,
+ Build.SUPPORTED_64_BIT_ABIS,
+ nativeLibFileName);
+ }
+ }
+
+ if (DEBUG) Log.v(LOGTAG, "Native 32-bit lib: " + path32 + ", 64-bit lib: " + path64);
+ return new String[] { path32, path64 };
+ }
+
+ private static String getLoadFromApkPath(String apkPath,
+ String[] abiList,
+ String nativeLibFileName)
+ throws WebViewFactory.MissingWebViewPackageException {
+ // Search the APK for a native library conforming to a listed ABI.
+ try (ZipFile z = new ZipFile(apkPath)) {
+ for (String abi : abiList) {
+ final String entry = "lib/" + abi + "/" + nativeLibFileName;
+ ZipEntry e = z.getEntry(entry);
+ if (e != null && e.getMethod() == ZipEntry.STORED) {
+ // Return a path formatted for dlopen() load from APK.
+ return apkPath + "!/" + entry;
+ }
+ }
+ } catch (IOException e) {
+ throw new WebViewFactory.MissingWebViewPackageException(e);
+ }
+ return "";
+ }
+
+ /**
+ * Sets the size of the memory area in which to store the relro section.
+ */
+ private static void setWebViewZygoteVmSize(long vmSize) {
+ SystemProperties.set(WebViewFactory.CHROMIUM_WEBVIEW_VMSIZE_SIZE_PROPERTY,
+ Long.toString(vmSize));
+ }
+
+ static native boolean nativeReserveAddressSpace(long addressSpaceToReserve);
+ static native boolean nativeCreateRelroFile(String lib32, String lib64,
+ String relro32, String relro64);
+ static native int nativeLoadWithRelroFile(String lib, String relro32, String relro64,
+ ClassLoader clazzLoader);
+}