1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 package org.chromium.android_webview;
6 
7 import android.content.Context;
8 import android.net.Uri;
9 
10 import org.chromium.android_webview.common.Flag;
11 import org.chromium.android_webview.common.FlagOverrideHelper;
12 import org.chromium.android_webview.common.PlatformServiceBridge;
13 import org.chromium.android_webview.common.ProductionSupportedFlagList;
14 import org.chromium.base.Callback;
15 import org.chromium.base.ThreadUtils;
16 import org.chromium.base.annotations.CalledByNative;
17 import org.chromium.base.annotations.JNINamespace;
18 import org.chromium.base.annotations.NativeMethods;
19 import org.chromium.base.task.PostTask;
20 import org.chromium.base.task.TaskTraits;
21 import org.chromium.content_public.browser.UiThreadTaskTraits;
22 
23 import java.util.ArrayList;
24 import java.util.List;
25 import java.util.Map;
26 
27 /**
28  * Implementations of various static methods, and also a home for static
29  * data structures that are meant to be shared between all webviews.
30  */
31 @JNINamespace("android_webview")
32 public class AwContentsStatics {
33 
34     private static ClientCertLookupTable sClientCertLookupTable;
35 
36     private static String sUnreachableWebDataUrl;
37 
38     private static boolean sRecordFullDocument;
39 
40     private static final String sSafeBrowsingWarmUpHelper =
41             "com.android.webview.chromium.SafeBrowsingWarmUpHelper";
42 
43     /**
44      * Return the client certificate lookup table.
45      */
getClientCertLookupTable()46     public static ClientCertLookupTable getClientCertLookupTable() {
47         ThreadUtils.assertOnUiThread();
48         if (sClientCertLookupTable == null) {
49             sClientCertLookupTable = new ClientCertLookupTable();
50         }
51         return sClientCertLookupTable;
52     }
53 
54     /**
55      * Clear client cert lookup table. Should only be called from UI thread.
56      */
clearClientCertPreferences(Runnable callback)57     public static void clearClientCertPreferences(Runnable callback) {
58         ThreadUtils.assertOnUiThread();
59         getClientCertLookupTable().clear();
60         AwContentsStaticsJni.get().clearClientCertPreferences(callback);
61     }
62 
63     @CalledByNative
clientCertificatesCleared(Runnable callback)64     private static void clientCertificatesCleared(Runnable callback) {
65         if (callback == null) return;
66         callback.run();
67     }
68 
getUnreachableWebDataUrl()69     public static String getUnreachableWebDataUrl() {
70         // Note that this method may be called from both IO and UI threads,
71         // but as it only retrieves a value of a constant from native, even if
72         // two calls will be running at the same time, this should not cause
73         // any harm.
74         if (sUnreachableWebDataUrl == null) {
75             sUnreachableWebDataUrl = AwContentsStaticsJni.get().getUnreachableWebDataUrl();
76         }
77         return sUnreachableWebDataUrl;
78     }
79 
setRecordFullDocument(boolean recordFullDocument)80     public static void setRecordFullDocument(boolean recordFullDocument) {
81         sRecordFullDocument = recordFullDocument;
82     }
83 
getRecordFullDocument()84     /* package */ static boolean getRecordFullDocument() {
85         return sRecordFullDocument;
86     }
87 
getProductVersion()88     public static String getProductVersion() {
89         return AwContentsStaticsJni.get().getProductVersion();
90     }
91 
setServiceWorkerIoThreadClient( AwContentsIoThreadClient ioThreadClient, AwBrowserContext browserContext)92     public static void setServiceWorkerIoThreadClient(
93             AwContentsIoThreadClient ioThreadClient, AwBrowserContext browserContext) {
94         AwContentsStaticsJni.get().setServiceWorkerIoThreadClient(ioThreadClient, browserContext);
95     }
96 
97     @CalledByNative
safeBrowsingAllowlistAssigned(Callback<Boolean> callback, boolean success)98     private static void safeBrowsingAllowlistAssigned(Callback<Boolean> callback, boolean success) {
99         if (callback == null) return;
100         callback.onResult(success);
101     }
102 
setSafeBrowsingAllowlist(List<String> urls, Callback<Boolean> callback)103     public static void setSafeBrowsingAllowlist(List<String> urls, Callback<Boolean> callback) {
104         String[] urlArray = urls.toArray(new String[urls.size()]);
105         if (callback == null) {
106             callback = b -> {
107             };
108         }
109         AwContentsStaticsJni.get().setSafeBrowsingAllowlist(urlArray, callback);
110     }
111 
112     @SuppressWarnings("NoContextGetApplicationContext")
initSafeBrowsing(Context context, final Callback<Boolean> callback)113     public static void initSafeBrowsing(Context context, final Callback<Boolean> callback) {
114         // Wrap the callback to make sure we always invoke it on the UI thread, as guaranteed by the
115         // API.
116         Callback<Boolean> wrapperCallback = b -> {
117             if (callback != null) {
118                 PostTask.runOrPostTask(UiThreadTaskTraits.DEFAULT, callback.bind(b));
119             }
120         };
121 
122         PlatformServiceBridge.getInstance().warmUpSafeBrowsing(
123                 context.getApplicationContext(), wrapperCallback);
124     }
125 
getSafeBrowsingPrivacyPolicyUrl()126     public static Uri getSafeBrowsingPrivacyPolicyUrl() {
127         return Uri.parse(AwContentsStaticsJni.get().getSafeBrowsingPrivacyPolicyUrl());
128     }
129 
setCheckClearTextPermitted(boolean permitted)130     public static void setCheckClearTextPermitted(boolean permitted) {
131         AwContentsStaticsJni.get().setCheckClearTextPermitted(permitted);
132     }
133 
logCommandLineForDebugging()134     public static void logCommandLineForDebugging() {
135         AwContentsStaticsJni.get().logCommandLineForDebugging();
136     }
137 
logFlagOverridesWithNative(Map<String, Boolean> flagOverrides)138     public static void logFlagOverridesWithNative(Map<String, Boolean> flagOverrides) {
139         // Do work asynchronously to avoid blocking startup.
140         PostTask.postTask(TaskTraits.THREAD_POOL_BEST_EFFORT, () -> {
141             FlagOverrideHelper helper =
142                     new FlagOverrideHelper(ProductionSupportedFlagList.sFlagList);
143             ArrayList<String> switches = new ArrayList<>();
144             ArrayList<String> features = new ArrayList<>();
145             for (Map.Entry<String, Boolean> entry : flagOverrides.entrySet()) {
146                 Flag flag = helper.getFlagForName(entry.getKey());
147                 boolean enabled = entry.getValue();
148                 if (flag.isBaseFeature()) {
149                     features.add(flag.getName() + (enabled ? ":enabled" : ":disabled"));
150                 } else if (enabled) {
151                     switches.add("--" + flag.getName());
152                 }
153                 // Only insert enabled switches; ignore explicitly disabled switches since this is
154                 // usually a NOOP.
155             }
156             AwContentsStaticsJni.get().logFlagMetrics(
157                     switches.toArray(new String[0]), features.toArray(new String[0]));
158         });
159     }
160 
161     /**
162      * Return the first substring consisting of the address of a physical location.
163      * @see {@link android.webkit.WebView#findAddress(String)}
164      *
165      * @param addr The string to search for addresses.
166      * @return the address, or if no address is found, return null.
167      */
findAddress(String addr)168     public static String findAddress(String addr) {
169         if (addr == null) {
170             throw new NullPointerException("addr is null");
171         }
172         return FindAddress.findAddress(addr);
173     }
174 
175     /**
176      * Returns true if WebView is running in multi process mode.
177      */
isMultiProcessEnabled()178     public static boolean isMultiProcessEnabled() {
179         return AwContentsStaticsJni.get().isMultiProcessEnabled();
180     }
181 
182     @NativeMethods
183     interface Natives {
logCommandLineForDebugging()184         void logCommandLineForDebugging();
logFlagMetrics(String[] switches, String[] features)185         void logFlagMetrics(String[] switches, String[] features);
186 
getSafeBrowsingPrivacyPolicyUrl()187         String getSafeBrowsingPrivacyPolicyUrl();
clearClientCertPreferences(Runnable callback)188         void clearClientCertPreferences(Runnable callback);
getUnreachableWebDataUrl()189         String getUnreachableWebDataUrl();
getProductVersion()190         String getProductVersion();
setServiceWorkerIoThreadClient( AwContentsIoThreadClient ioThreadClient, AwBrowserContext browserContext)191         void setServiceWorkerIoThreadClient(
192                 AwContentsIoThreadClient ioThreadClient, AwBrowserContext browserContext);
setSafeBrowsingAllowlist(String[] urls, Callback<Boolean> callback)193         void setSafeBrowsingAllowlist(String[] urls, Callback<Boolean> callback);
setCheckClearTextPermitted(boolean permitted)194         void setCheckClearTextPermitted(boolean permitted);
isMultiProcessEnabled()195         boolean isMultiProcessEnabled();
196     }
197 }
198