Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code

Side by Side Diff: libadblockplus-android-webview/src/org/adblockplus/libadblockplus/android/webview/AdblockWebView.java

Issue 29671734: Issue 6265 - Create shared AdblockEngine instance in AdblockWebView in background (Closed)
Patch Set: Sergey's comments Created Jan. 22, 2018, 6:19 a.m.
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
View unified diff | Download patch
OLDNEW
1 /* 1 /*
2 * This file is part of Adblock Plus <https://adblockplus.org/>, 2 * This file is part of Adblock Plus <https://adblockplus.org/>,
3 * Copyright (C) 2006-present eyeo GmbH 3 * Copyright (C) 2006-present eyeo GmbH
4 * 4 *
5 * Adblock Plus is free software: you can redistribute it and/or modify 5 * Adblock Plus is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 3 as 6 * it under the terms of the GNU General Public License version 3 as
7 * published by the Free Software Foundation. 7 * published by the Free Software Foundation.
8 * 8 *
9 * Adblock Plus is distributed in the hope that it will be useful, 9 * Adblock Plus is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
(...skipping 30 matching lines...) Expand all
41 import android.webkit.WebChromeClient; 41 import android.webkit.WebChromeClient;
42 import android.webkit.WebResourceRequest; // makes android min version to be 21 42 import android.webkit.WebResourceRequest; // makes android min version to be 21
43 import android.webkit.WebResourceResponse; 43 import android.webkit.WebResourceResponse;
44 import android.webkit.WebStorage; 44 import android.webkit.WebStorage;
45 import android.webkit.WebView; 45 import android.webkit.WebView;
46 import android.webkit.WebViewClient; 46 import android.webkit.WebViewClient;
47 47
48 import org.adblockplus.libadblockplus.FilterEngine; 48 import org.adblockplus.libadblockplus.FilterEngine;
49 import org.adblockplus.libadblockplus.Subscription; 49 import org.adblockplus.libadblockplus.Subscription;
50 import org.adblockplus.libadblockplus.android.AdblockEngine; 50 import org.adblockplus.libadblockplus.android.AdblockEngine;
51 import org.adblockplus.libadblockplus.android.AdblockEngineProvider;
52 import org.adblockplus.libadblockplus.android.SingleInstanceEngineProvider;
51 import org.adblockplus.libadblockplus.android.Utils; 53 import org.adblockplus.libadblockplus.android.Utils;
52 54
53 import java.io.IOException; 55 import java.io.IOException;
54 import java.util.Collections; 56 import java.util.Collections;
55 import java.util.HashMap; 57 import java.util.HashMap;
56 import java.util.List; 58 import java.util.List;
57 import java.util.Map; 59 import java.util.Map;
58 import java.util.concurrent.CountDownLatch; 60 import java.util.concurrent.CountDownLatch;
59 import java.util.concurrent.atomic.AtomicBoolean; 61 import java.util.concurrent.atomic.AtomicBoolean;
60 import java.util.regex.Pattern; 62 import java.util.regex.Pattern;
(...skipping 27 matching lines...) Expand all
88 90
89 private static final Pattern RE_JS = Pattern.compile("\\.js$", Pattern.CASE_IN SENSITIVE); 91 private static final Pattern RE_JS = Pattern.compile("\\.js$", Pattern.CASE_IN SENSITIVE);
90 private static final Pattern RE_CSS = Pattern.compile("\\.css$", Pattern.CASE_ INSENSITIVE); 92 private static final Pattern RE_CSS = Pattern.compile("\\.css$", Pattern.CASE_ INSENSITIVE);
91 private static final Pattern RE_IMAGE = Pattern.compile("\\.(?:gif|png|jpe?g|b mp|ico)$", Pattern.CASE_INSENSITIVE); 93 private static final Pattern RE_IMAGE = Pattern.compile("\\.(?:gif|png|jpe?g|b mp|ico)$", Pattern.CASE_INSENSITIVE);
92 private static final Pattern RE_FONT = Pattern.compile("\\.(?:ttf|woff)$", Pat tern.CASE_INSENSITIVE); 94 private static final Pattern RE_FONT = Pattern.compile("\\.(?:ttf|woff)$", Pat tern.CASE_INSENSITIVE);
93 private static final Pattern RE_HTML = Pattern.compile("\\.html?$", Pattern.CA SE_INSENSITIVE); 95 private static final Pattern RE_HTML = Pattern.compile("\\.html?$", Pattern.CA SE_INSENSITIVE);
94 96
95 private volatile boolean addDomListener = true; 97 private volatile boolean addDomListener = true;
96 private boolean adblockEnabled = true; 98 private boolean adblockEnabled = true;
97 private boolean debugMode; 99 private boolean debugMode;
98 private AdblockEngine adblockEngine; 100 private AdblockEngineProvider provider;
99 private boolean disposeEngine;
100 private Integer loadError; 101 private Integer loadError;
101 private int allowDrawDelay = ALLOW_DRAW_DELAY; 102 private int allowDrawDelay = ALLOW_DRAW_DELAY;
102 private WebChromeClient extWebChromeClient; 103 private WebChromeClient extWebChromeClient;
103 private WebViewClient extWebViewClient; 104 private WebViewClient extWebViewClient;
104 private WebViewClient intWebViewClient; 105 private WebViewClient intWebViewClient;
105 private Map<String, String> url2Referrer = Collections.synchronizedMap(new Has hMap<String, String>()); 106 private Map<String, String> url2Referrer = Collections.synchronizedMap(new Has hMap<String, String>());
106 private String url; 107 private String url;
107 private String domain; 108 private String domain;
108 private String injectJs; 109 private String injectJs;
109 private CountDownLatch elemHideLatch; 110 private CountDownLatch elemHideLatch;
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after
177 applyAdblockEnabled(); 178 applyAdblockEnabled();
178 } 179 }
179 180
180 public boolean isDebugMode() 181 public boolean isDebugMode()
181 { 182 {
182 return debugMode; 183 return debugMode;
183 } 184 }
184 185
185 /** 186 /**
186 * Set to true to see debug log output int AdblockWebView and JS console 187 * Set to true to see debug log output int AdblockWebView and JS console
188 * Should be set before first URL loading if using internal AdblockEngineProvi der
187 * @param debugMode is debug mode 189 * @param debugMode is debug mode
188 */ 190 */
189 public void setDebugMode(boolean debugMode) 191 public void setDebugMode(boolean debugMode)
190 { 192 {
191 this.debugMode = debugMode; 193 this.debugMode = debugMode;
192 } 194 }
193 195
194 private void d(String message) 196 private void d(String message)
195 { 197 {
196 if (debugMode) 198 if (debugMode)
(...skipping 28 matching lines...) Expand all
225 .replace(DEBUG_TOKEN, (debugMode ? "" : "//")); 227 .replace(DEBUG_TOKEN, (debugMode ? "" : "//"));
226 } 228 }
227 229
228 private void runScript(String script) 230 private void runScript(String script)
229 { 231 {
230 d("runScript started"); 232 d("runScript started");
231 evaluateJavascript(script, null); 233 evaluateJavascript(script, null);
232 d("runScript finished"); 234 d("runScript finished");
233 } 235 }
234 236
235 public AdblockEngine getAdblockEngine() 237 public void setProvider(final AdblockEngineProvider provider)
236 { 238 {
237 return adblockEngine; 239 if (this.provider != null && provider != null && this.provider == provider)
238 }
239
240 /**
241 * Set external adblockEngine. A new (internal) is created automatically if no t set
242 * Don't forget to invoke {@link #dispose(Runnable)} later and dispose externa l adblockEngine
243 * @param adblockEngine external adblockEngine
244 */
245 public void setAdblockEngine(final AdblockEngine adblockEngine)
246 {
247 if (this.adblockEngine != null && adblockEngine != null && this.adblockEngin e == adblockEngine)
248 { 240 {
249 return; 241 return;
250 } 242 }
251 243
252 final Runnable setRunnable = new Runnable() 244 final Runnable setRunnable = new Runnable()
253 { 245 {
254 @Override 246 @Override
255 public void run() 247 public void run()
256 { 248 {
257 AdblockWebView.this.adblockEngine = adblockEngine; 249 AdblockWebView.this.provider = provider;
258 AdblockWebView.this.disposeEngine = false; 250 if (AdblockWebView.this.provider != null)
251 {
252 AdblockWebView.this.provider.retain(true); // asynchronously
253 }
259 } 254 }
260 }; 255 };
261 256
262 if (this.adblockEngine != null && disposeEngine) 257 if (this.provider != null)
263 { 258 {
264 // as adblockEngine can be busy with elemhide thread we need to use callba ck 259 // as adblockEngine can be busy with elemhide thread we need to use callba ck
265 this.dispose(setRunnable); 260 this.dispose(setRunnable);
266 } 261 }
267 else 262 else
268 { 263 {
269 setRunnable.run(); 264 setRunnable.run();
270 } 265 }
271 } 266 }
272 267
(...skipping 545 matching lines...) Expand 10 before | Expand all | Expand 10 after
818 { 813 {
819 super.onReceivedLoginRequest(view, realm, account, args); 814 super.onReceivedLoginRequest(view, realm, account, args);
820 } 815 }
821 } 816 }
822 817
823 protected WebResourceResponse shouldInterceptRequest( 818 protected WebResourceResponse shouldInterceptRequest(
824 WebView webview, String url, boolean isMainFrame, 819 WebView webview, String url, boolean isMainFrame,
825 boolean isXmlHttpRequest, String[] referrerChainArray) 820 boolean isXmlHttpRequest, String[] referrerChainArray)
826 { 821 {
827 // if dispose() was invoke, but the page is still loading then just let it go 822 // if dispose() was invoke, but the page is still loading then just let it go
828 if (adblockEngine == null) 823 if (provider.getCounter() == 0)
829 { 824 {
830 e("FilterEngine already disposed, allow loading"); 825 e("FilterEngine already disposed, allow loading");
831 826
832 // allow loading by returning null 827 // allow loading by returning null
833 return null; 828 return null;
834 } 829 }
835 830
836 if (isMainFrame) 831 if (isMainFrame)
837 { 832 {
838 // never blocking main frame requests, just subrequests 833 // never blocking main frame requests, just subrequests
839 w(url + " is main frame, allow loading"); 834 w(url + " is main frame, allow loading");
840 835
841 // allow loading by returning null 836 // allow loading by returning null
842 return null; 837 return null;
843 } 838 }
844 839
845 // whitelisted 840 // whitelisted
846 if (adblockEngine.isDomainWhitelisted(url, referrerChainArray)) 841 if (provider.getEngine().isDomainWhitelisted(url, referrerChainArray))
847 { 842 {
848 w(url + " domain is whitelisted, allow loading"); 843 w(url + " domain is whitelisted, allow loading");
849 844
850 // allow loading by returning null 845 // allow loading by returning null
851 return null; 846 return null;
852 } 847 }
853 848
854 if (adblockEngine.isDocumentWhitelisted(url, referrerChainArray)) 849 if (provider.getEngine().isDocumentWhitelisted(url, referrerChainArray))
855 { 850 {
856 w(url + " document is whitelisted, allow loading"); 851 w(url + " document is whitelisted, allow loading");
857 852
858 // allow loading by returning null 853 // allow loading by returning null
859 return null; 854 return null;
860 } 855 }
861 856
862 // determine the content 857 // determine the content
863 FilterEngine.ContentType contentType; 858 FilterEngine.ContentType contentType;
864 if (isXmlHttpRequest) 859 if (isXmlHttpRequest)
(...skipping 22 matching lines...) Expand all
887 { 882 {
888 contentType = FilterEngine.ContentType.SUBDOCUMENT; 883 contentType = FilterEngine.ContentType.SUBDOCUMENT;
889 } 884 }
890 else 885 else
891 { 886 {
892 contentType = FilterEngine.ContentType.OTHER; 887 contentType = FilterEngine.ContentType.OTHER;
893 } 888 }
894 } 889 }
895 890
896 // check if we should block 891 // check if we should block
897 if (adblockEngine.matches(url, contentType, referrerChainArray)) 892 if (provider.getEngine().matches(url, contentType, referrerChainArray))
898 { 893 {
899 w("Blocked loading " + url); 894 w("Blocked loading " + url);
900 895
901 // if we should block, return empty response which results in 'errorLoad ing' callback 896 // if we should block, return empty response which results in 'errorLoad ing' callback
902 return new WebResourceResponse("text/plain", "UTF-8", null); 897 return new WebResourceResponse("text/plain", "UTF-8", null);
903 } 898 }
904 899
905 d("Allowed loading " + url); 900 d("Allowed loading " + url);
906 901
907 // continue by returning null 902 // continue by returning null
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
949 addJavascriptInterface(this, BRIDGE); 944 addJavascriptInterface(this, BRIDGE);
950 initClients(); 945 initClients();
951 } 946 }
952 947
953 private void initClients() 948 private void initClients()
954 { 949 {
955 intWebViewClient = new AdblockWebViewClient(); 950 intWebViewClient = new AdblockWebViewClient();
956 applyAdblockEnabled(); 951 applyAdblockEnabled();
957 } 952 }
958 953
959 private void createAdblockEngine()
960 {
961 w("Creating AdblockEngine");
962
963 // assuming `this.debugMode` can be used as `developmentBuild` value
964 adblockEngine = AdblockEngine
965 .builder(
966 AdblockEngine.generateAppInfo(this.getContext(), debugMode),
967 this.getContext().getDir(AdblockEngine.BASE_PATH_DIRECTORY, Context.MODE _PRIVATE).getAbsolutePath())
968 .enableElementHiding(true)
969 .build();
970 }
971
972 private class ElemHideThread extends Thread 954 private class ElemHideThread extends Thread
973 { 955 {
974 private String selectorsString; 956 private String selectorsString;
975 private CountDownLatch finishedLatch; 957 private CountDownLatch finishedLatch;
976 private AtomicBoolean isCancelled; 958 private AtomicBoolean isCancelled;
977 959
978 public ElemHideThread(CountDownLatch finishedLatch) 960 public ElemHideThread(CountDownLatch finishedLatch)
979 { 961 {
980 this.finishedLatch = finishedLatch; 962 this.finishedLatch = finishedLatch;
981 isCancelled = new AtomicBoolean(false); 963 isCancelled = new AtomicBoolean(false);
982 } 964 }
983 965
984 @Override 966 @Override
985 public void run() 967 public void run()
986 { 968 {
987 try 969 try
988 { 970 {
989 if (adblockEngine == null) 971 if (provider.getCounter() == 0)
990 { 972 {
991 w("FilterEngine already disposed"); 973 w("FilterEngine already disposed");
992 selectorsString = EMPTY_ELEMHIDE_ARRAY_STRING; 974 selectorsString = EMPTY_ELEMHIDE_ARRAY_STRING;
993 } 975 }
994 else 976 else
995 { 977 {
996 String[] referrers = new String[] 978 String[] referrers = new String[]
997 { 979 {
998 url 980 url
999 }; 981 };
1000 982
1001 List<Subscription> subscriptions = adblockEngine.getFilterEngine().get ListedSubscriptions(); 983 List<Subscription> subscriptions = provider
984 .getEngine()
985 .getFilterEngine()
986 .getListedSubscriptions();
987
1002 try 988 try
1003 { 989 {
1004 d("Listed subscriptions: " + subscriptions.size()); 990 d("Listed subscriptions: " + subscriptions.size());
1005 if (debugMode) 991 if (debugMode)
1006 { 992 {
1007 for (Subscription eachSubscription : subscriptions) 993 for (Subscription eachSubscription : subscriptions)
1008 { 994 {
1009 d("Subscribed to " 995 d("Subscribed to "
1010 + (eachSubscription.isDisabled() ? "disabled" : "enabled") 996 + (eachSubscription.isDisabled() ? "disabled" : "enabled")
1011 + " " + eachSubscription); 997 + " " + eachSubscription);
1012 } 998 }
1013 } 999 }
1014 } 1000 }
1015 finally 1001 finally
1016 { 1002 {
1017 for (Subscription eachSubscription : subscriptions) 1003 for (Subscription eachSubscription : subscriptions)
1018 { 1004 {
1019 eachSubscription.dispose(); 1005 eachSubscription.dispose();
1020 } 1006 }
1021 } 1007 }
1022 1008
1023 d("Requesting elemhide selectors from AdblockEngine for " + url + " in " + this); 1009 d("Requesting elemhide selectors from AdblockEngine for " + url + " in " + this);
1024 List<String> selectors = adblockEngine.getElementHidingSelectors(url, domain, referrers); 1010 List<String> selectors = provider
1011 .getEngine()
1012 .getElementHidingSelectors(url, domain, referrers);
1013
1025 d("Finished requesting elemhide selectors, got " + selectors.size() + " in " + this); 1014 d("Finished requesting elemhide selectors, got " + selectors.size() + " in " + this);
1026 selectorsString = Utils.stringListToJsonArray(selectors); 1015 selectorsString = Utils.stringListToJsonArray(selectors);
1027 } 1016 }
1028 } 1017 }
1029 finally 1018 finally
1030 { 1019 {
1031 if (!isCancelled.get()) 1020 if (!isCancelled.get())
1032 { 1021 {
1033 finish(selectorsString); 1022 finish(selectorsString);
1034 } 1023 }
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
1088 w("elemHideThread set to null"); 1077 w("elemHideThread set to null");
1089 elemHideThread = null; 1078 elemHideThread = null;
1090 } 1079 }
1091 } 1080 }
1092 }; 1081 };
1093 1082
1094 private void initAbpLoading() 1083 private void initAbpLoading()
1095 { 1084 {
1096 getSettings().setJavaScriptEnabled(true); 1085 getSettings().setJavaScriptEnabled(true);
1097 buildInjectJs(); 1086 buildInjectJs();
1087 ensureProvider();
1088 }
1098 1089
1099 if (adblockEngine == null) 1090 private void ensureProvider()
1091 {
1092 // if AdblockWebView works as drop-in replacement for WebView 'provider' is not set.
1093 // Thus AdblockWebView is using SingleInstanceEngineProvider instance
1094 if (provider == null)
1100 { 1095 {
1101 createAdblockEngine(); 1096 setProvider(new SingleInstanceEngineProvider(
1102 disposeEngine = true; 1097 getContext(), AdblockEngine.BASE_PATH_DIRECTORY, debugMode));
1103 } 1098 }
1104 } 1099 }
1105 1100
1106 private void startAbpLoading(String newUrl) 1101 private void startAbpLoading(String newUrl)
1107 { 1102 {
1108 d("Start loading " + newUrl); 1103 d("Start loading " + newUrl);
1109 1104
1110 loading = true; 1105 loading = true;
1111 addDomListener = true; 1106 addDomListener = true;
1112 elementsHidden = false; 1107 elementsHidden = false;
1113 loadError = null; 1108 loadError = null;
1114 url = newUrl; 1109 url = newUrl;
1115 1110
1116 if (url != null && adblockEngine != null) 1111 if (url != null)
1117 { 1112 {
1118 try 1113 try
1119 { 1114 {
1120 domain = adblockEngine.getFilterEngine().getHostFromURL(url); 1115 d("Waiting for adblock engine");
1116 provider.waitForReady();
1117
1118 domain = provider.getEngine().getFilterEngine().getHostFromURL(url);
1121 if (domain == null) 1119 if (domain == null)
1122 { 1120 {
1123 throw new RuntimeException("Failed to extract domain from " + url); 1121 throw new RuntimeException("Failed to extract domain from " + url);
1124 } 1122 }
1125 1123
1126 d("Extracted domain " + domain + " from " + url); 1124 d("Extracted domain " + domain + " from " + url);
1127 } 1125 }
1128 catch (Throwable t) 1126 catch (Throwable t)
1129 { 1127 {
1130 e("Failed to extract domain from " + url, t); 1128 e("Failed to extract domain from " + url, t);
(...skipping 242 matching lines...) Expand 10 before | Expand all | Expand 10 after
1373 { 1371 {
1374 w("Interrupted, returning empty selectors list"); 1372 w("Interrupted, returning empty selectors list");
1375 return EMPTY_ELEMHIDE_ARRAY_STRING; 1373 return EMPTY_ELEMHIDE_ARRAY_STRING;
1376 } 1374 }
1377 } 1375 }
1378 } 1376 }
1379 1377
1380 private void doDispose() 1378 private void doDispose()
1381 { 1379 {
1382 w("Disposing AdblockEngine"); 1380 w("Disposing AdblockEngine");
1383 adblockEngine.dispose(); 1381 provider.release();
1384 adblockEngine = null;
1385
1386 disposeEngine = false;
1387 } 1382 }
1388 1383
1389 private class DisposeRunnable implements Runnable 1384 private class DisposeRunnable implements Runnable
1390 { 1385 {
1391 private Runnable disposeFinished; 1386 private Runnable disposeFinished;
1392 1387
1393 private DisposeRunnable(Runnable disposeFinished) 1388 private DisposeRunnable(Runnable disposeFinished)
1394 { 1389 {
1395 this.disposeFinished = disposeFinished; 1390 this.disposeFinished = disposeFinished;
1396 } 1391 }
1397 1392
1398 @Override 1393 @Override
1399 public void run() 1394 public void run()
1400 { 1395 {
1401 if (disposeEngine) 1396 doDispose();
1402 {
1403 doDispose();
1404 }
1405 1397
1406 if (disposeFinished != null) 1398 if (disposeFinished != null)
1407 { 1399 {
1408 disposeFinished.run(); 1400 disposeFinished.run();
1409 } 1401 }
1410 } 1402 }
1411 } 1403 }
1412 1404
1413 /** 1405 /**
1414 * Dispose AdblockWebView and internal adblockEngine if it was created 1406 * Dispose AdblockWebView and internal adblockEngine if it was created
1415 * If external AdblockEngine was passed using `setAdblockEngine()` it should b e disposed explicitly 1407 * If external AdblockEngine was passed using `setAdblockEngine()` it should b e disposed explicitly
1416 * Warning: runnable can be invoked from background thread 1408 * Warning: runnable can be invoked from background thread
1417 * @param disposeFinished runnable to run when AdblockWebView is disposed 1409 * @param disposeFinished runnable to run when AdblockWebView is disposed
1418 */ 1410 */
1419 public void dispose(final Runnable disposeFinished) 1411 public void dispose(final Runnable disposeFinished)
1420 { 1412 {
1421 d("Dispose invoked"); 1413 d("Dispose invoked");
1422 1414
1415 if (provider == null)
1416 {
1417 d("No internal AdblockEngineProvider created");
1418 return;
1419 }
1420
1423 stopLoading(); 1421 stopLoading();
1424 1422
1425 removeJavascriptInterface(BRIDGE);
1426 if (!disposeEngine)
1427 {
1428 adblockEngine = null;
1429 }
1430
1431 DisposeRunnable disposeRunnable = new DisposeRunnable(disposeFinished); 1423 DisposeRunnable disposeRunnable = new DisposeRunnable(disposeFinished);
1432 synchronized (elemHideThreadLockObject) 1424 synchronized (elemHideThreadLockObject)
1433 { 1425 {
1434 if (elemHideThread != null) 1426 if (elemHideThread != null)
1435 { 1427 {
1436 w("Busy with elemhide selectors, delayed disposing scheduled"); 1428 w("Busy with elemhide selectors, delayed disposing scheduled");
1437 elemHideThread.setFinishedRunnable(disposeRunnable); 1429 elemHideThread.setFinishedRunnable(disposeRunnable);
1438 } 1430 }
1439 else 1431 else
1440 { 1432 {
1441 disposeRunnable.run(); 1433 disposeRunnable.run();
1442 } 1434 }
1443 } 1435 }
1444 } 1436 }
1445 } 1437 }
OLDNEW
« no previous file with comments | « libadblockplus-android-webview/pom.xml ('k') | libadblockplus-android-webviewapp/AndroidManifest.xml » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld