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

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

Issue 29671734: Issue 6265 - Create shared AdblockEngine instance in AdblockWebView in background (Closed)
Patch Set: Created Jan. 17, 2018, 11:48 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
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details. 12 * GNU General Public License for more details.
13 * 13 *
14 * You should have received a copy of the GNU General Public License 14 * You should have received a copy of the GNU General Public License
15 * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>. 15 * along with Adblock Plus. If not, see <http://www.gnu.org/licenses/>.
16 */ 16 */
17 package org.adblockplus.libadblockplus.android;
17 18
18 package org.adblockplus.libadblockplus.android.settings; 19 import org.adblockplus.libadblockplus.IsAllowedConnectionCallback;
19 20
20 import android.content.Context; 21 import android.content.Context;
21 import android.content.SharedPreferences; 22 import android.content.SharedPreferences;
22 import android.net.ConnectivityManager; 23 import android.net.ConnectivityManager;
23 import android.util.Log; 24 import android.util.Log;
24 25
25 import org.adblockplus.libadblockplus.IsAllowedConnectionCallback;
26 import org.adblockplus.libadblockplus.android.AdblockEngine;
27 import org.adblockplus.libadblockplus.android.AndroidWebRequestResourceWrapper;
28 import org.adblockplus.libadblockplus.android.Utils;
29
30 import java.util.Map; 26 import java.util.Map;
31 import java.util.concurrent.CountDownLatch; 27 import java.util.concurrent.CountDownLatch;
32 import java.util.concurrent.atomic.AtomicInteger; 28 import java.util.concurrent.atomic.AtomicInteger;
33 29
34 /** 30 /**
35 * AdblockHelper shared resources 31 * Provides single instance of AdblockEngine shared between registered clients
36 * (singleton)
37 */ 32 */
38 public class AdblockHelper 33 public class SingleInstanceEngineProvider implements AdblockEngineProvider
39 { 34 {
40 private static final String TAG = Utils.getTag(AdblockHelper.class); 35 private static final String TAG = Utils.getTag(SingleInstanceEngineProvider.cl ass);
41
42 /**
43 * Suggested preference name to store settings
44 */
45 public static final String PREFERENCE_NAME = "ADBLOCK";
46
47 /**
48 * Suggested preference name to store intercepted subscription requests
49 */
50 public static final String PRELOAD_PREFERENCE_NAME = "ADBLOCK_PRELOAD";
51 private static AdblockHelper _instance;
52 36
53 private Context context; 37 private Context context;
54 private String basePath; 38 private String basePath;
55 private boolean developmentBuild; 39 private boolean developmentBuild;
56 private String settingsPreferenceName;
57 private String preloadedPreferenceName; 40 private String preloadedPreferenceName;
58 private Map<String, Integer> urlToResourceIdMap; 41 private Map<String, Integer> urlToResourceIdMap;
59 private AdblockEngine engine; 42 private AdblockEngine engine;
60 private AdblockSettingsStorage storage;
61 private CountDownLatch engineCreated; 43 private CountDownLatch engineCreated;
62 private Long v8IsolateProviderPtr; 44 private Long v8IsolateProviderPtr;
45 private Runnable engineCreatedCallback;
46 private Runnable engineDisposedCallback;
63 47
64 /* 48 /*
65 Simple ARC management for AdblockEngine 49 Simple ARC management for AdblockEngine
66 Use `retain` and `release` 50 Use `retain` and `release`
67 */ 51 */
68 52
69 private AtomicInteger referenceCounter = new AtomicInteger(0); 53 private AtomicInteger referenceCounter = new AtomicInteger(0);
70 54
71 // singleton
72 protected AdblockHelper()
73 {
74 // prevents instantiation
75 }
76
77 /**
78 * Use to get AdblockHelper instance
79 * @return adblock instance
80 */
81 public static synchronized AdblockHelper get()
82 {
83 if (_instance == null)
84 {
85 _instance = new AdblockHelper();
86 }
87
88 return _instance;
89 }
90
91 public AdblockEngine getEngine()
92 {
93 return engine;
94 }
95
96 public AdblockSettingsStorage getStorage()
97 {
98 return storage;
99 }
100
101 /** 55 /**
102 * Init with context 56 * Init with context
103 * @param context application context 57 * @param context application context
104 * @param basePath file system root to store files 58 * @param basePath file system root to store files
105 * 59 *
106 * Adblock Plus library will download subscription files and s tore them on 60 * Adblock Plus library will download subscription files and s tore them on
107 * the path passed. The path should exist and the directory co ntent should not be 61 * the path passed. The path should exist and the directory co ntent should not be
108 * cleared out occasionally. Using `context.getCacheDir().getA bsolutePath()` is not 62 * cleared out occasionally. Using `context.getCacheDir().getA bsolutePath()` is not
109 * recommended because it can be cleared by the system. 63 * recommended because it can be cleared by the system.
110 * @param developmentBuild debug or release? 64 * @param developmentBuild debug or release?
111 * @param preferenceName Shared Preferences name to store adblock settings
112 */ 65 */
113 public AdblockHelper init(Context context, String basePath, 66 public SingleInstanceEngineProvider(Context context, String basePath, boolean developmentBuild)
114 boolean developmentBuild, String preferenceName)
115 { 67 {
116 this.context = context.getApplicationContext(); 68 this.context = context.getApplicationContext();
117 this.basePath = basePath; 69 this.basePath = basePath;
118 this.developmentBuild = developmentBuild; 70 this.developmentBuild = developmentBuild;
119 this.settingsPreferenceName = preferenceName;
120 return this;
121 } 71 }
122 72
123 /** 73 /**
124 * Use preloaded subscriptions 74 * Use preloaded subscriptions
125 * @param preferenceName Shared Preferences name to store intercepted requests stats 75 * @param preferenceName Shared Preferences name to store intercepted requests stats
126 * @param urlToResourceIdMap 76 * @param urlToResourceIdMap
127 */ 77 */
128 public AdblockHelper preloadSubscriptions(String preferenceName, Map<String, I nteger> urlToResourceIdMap) 78 public SingleInstanceEngineProvider preloadSubscriptions(String preferenceName ,
79 Map<String, Integer> urlToResourceIdMap)
129 { 80 {
130 this.preloadedPreferenceName = preferenceName; 81 this.preloadedPreferenceName = preferenceName;
131 this.urlToResourceIdMap = urlToResourceIdMap; 82 this.urlToResourceIdMap = urlToResourceIdMap;
132 return this; 83 return this;
133 } 84 }
134 85
135 public AdblockHelper useV8IsolateProvider(long ptr) 86 public SingleInstanceEngineProvider useV8IsolateProvider(long ptr)
136 { 87 {
137 this.v8IsolateProviderPtr = ptr; 88 this.v8IsolateProviderPtr = ptr;
138 return this; 89 return this;
139 } 90 }
140 91
92 public SingleInstanceEngineProvider setEngineCreatedCallback(Runnable callback )
93 {
94 this.engineCreatedCallback = callback;
95 return this;
96 }
97
98 public SingleInstanceEngineProvider setEngineDisposedCallback(Runnable callbac k)
99 {
100 this.engineDisposedCallback = callback;
101 return this;
102 }
103
141 private void createAdblock() 104 private void createAdblock()
142 { 105 {
143 ConnectivityManager connectivityManager = 106 ConnectivityManager connectivityManager =
144 (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVIC E); 107 (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVIC E);
145 IsAllowedConnectionCallback isAllowedConnectionCallback = new IsAllowedConne ctionCallbackImpl(connectivityManager); 108 IsAllowedConnectionCallback isAllowedConnectionCallback =
109 new IsAllowedConnectionCallbackImpl(connectivityManager);
146 110
147 Log.d(TAG, "Creating adblock engine ..."); 111 Log.d(TAG, "Creating adblock engine ...");
148 112
149 // read and apply current settings
150 SharedPreferences settingsPrefs = context.getSharedPreferences(
151 settingsPreferenceName,
152 Context.MODE_PRIVATE);
153 storage = new SharedPrefsStorage(settingsPrefs);
154
155 AdblockEngine.Builder builder = AdblockEngine 113 AdblockEngine.Builder builder = AdblockEngine
156 .builder( 114 .builder(
157 AdblockEngine.generateAppInfo(context, developmentBuild), 115 AdblockEngine.generateAppInfo(context, developmentBuild),
158 basePath) 116 basePath)
159 .setIsAllowedConnectionCallback(isAllowedConnectionCallback) 117 .setIsAllowedConnectionCallback(isAllowedConnectionCallback)
160 .enableElementHiding(true); 118 .enableElementHiding(true);
161 119
162 if (v8IsolateProviderPtr != null) 120 if (v8IsolateProviderPtr != null)
163 { 121 {
164 builder.useV8IsolateProvider(v8IsolateProviderPtr); 122 builder.useV8IsolateProvider(v8IsolateProviderPtr);
165 } 123 }
166 124
167 // if preloaded subscriptions provided 125 // if preloaded subscriptions provided
168 if (preloadedPreferenceName != null) 126 if (preloadedPreferenceName != null)
169 { 127 {
170 SharedPreferences preloadedSubscriptionsPrefs = context.getSharedPreferenc es( 128 SharedPreferences preloadedSubscriptionsPrefs = context.getSharedPreferenc es(
171 preloadedPreferenceName, 129 preloadedPreferenceName,
172 Context.MODE_PRIVATE); 130 Context.MODE_PRIVATE);
173 builder.preloadSubscriptions( 131 builder.preloadSubscriptions(
174 context, 132 context,
175 urlToResourceIdMap, 133 urlToResourceIdMap,
176 new AndroidWebRequestResourceWrapper.SharedPrefsStorage(preloadedSubscri ptionsPrefs)); 134 new AndroidWebRequestResourceWrapper.SharedPrefsStorage(preloadedSubscri ptionsPrefs));
177 } 135 }
178 136
179 engine = builder.build(); 137 engine = builder.build();
180 138
181 Log.d(TAG, "AdblockHelper engine created"); 139 Log.d(TAG, "AdblockHelper engine created");
182 140
183 AdblockSettings settings = storage.load(); 141 // sometimes we need to init AdblockEngine instance, eg. set user settings
184 if (settings != null) 142 if (engineCreatedCallback != null)
185 { 143 {
186 Log.d(TAG, "Applying saved adblock settings to adblock engine"); 144 engineCreatedCallback.run();
187 // apply last saved settings to adblock engine
188
189 // all the settings except `enabled` and whitelisted domains list
190 // are saved by adblock engine itself
191 engine.setEnabled(settings.isAdblockEnabled());
192 engine.setWhitelistedDomains(settings.getWhitelistedDomains());
193
194 // allowed connection type is saved by filter engine but we need to overri de it
195 // as filter engine can be not created when changing
196 String connectionType = (settings.getAllowedConnectionType() != null
197 ? settings.getAllowedConnectionType().getValue()
198 : null);
199 engine.getFilterEngine().setAllowedConnectionType(connectionType);
200 }
201 else
202 {
203 Log.w(TAG, "No saved adblock settings");
204 } 145 }
205 } 146 }
206 147
207 /** 148 @Override
208 * Wait until everything is ready (used for `retain(true)`)
209 * Warning: locks current thread
210 */
211 public void waitForReady()
212 {
213 if (engineCreated == null)
214 {
215 throw new RuntimeException("AdblockHelper Plus usage exception: call retai n(true) first");
216 }
217
218 try
219 {
220 Log.d(TAG, "Waiting for ready ...");
221 engineCreated.await();
222 Log.d(TAG, "Ready");
223 }
224 catch (InterruptedException e)
225 {
226 Log.w(TAG, "Interrupted", e);
227 }
228 }
229
230 private void disposeAdblock()
231 {
232 Log.w(TAG, "Disposing adblock engine");
233
234 engine.dispose();
235 engine = null;
236
237 storage = null;
238 }
239
240 /**
241 * Get registered clients count
242 * @return registered clients count
243 */
244 public int getCounter()
245 {
246 return referenceCounter.get();
247 }
248
249 /**
250 * Register AdblockHelper engine client
251 * @param asynchronous If `true` engines will be created in background thread without locking of
252 * current thread. Use waitForReady() before getEngine() l ater.
253 * If `false` locks current thread.
254 * @return if a new instance is allocated
255 */
256 public synchronized boolean retain(boolean asynchronous) 149 public synchronized boolean retain(boolean asynchronous)
257 { 150 {
258 boolean firstInstance = false; 151 boolean firstInstance = false;
259 152
260 if (referenceCounter.getAndIncrement() == 0) 153 if (referenceCounter.getAndIncrement() == 0)
261 { 154 {
262 firstInstance = true; 155 firstInstance = true;
263 156
264 if (!asynchronous) 157 if (!asynchronous)
265 { 158 {
(...skipping 13 matching lines...) Expand all
279 172
280 // unlock waiting client thread 173 // unlock waiting client thread
281 engineCreated.countDown(); 174 engineCreated.countDown();
282 } 175 }
283 }).start(); 176 }).start();
284 } 177 }
285 } 178 }
286 return firstInstance; 179 return firstInstance;
287 } 180 }
288 181
289 /** 182 @Override
290 * Unregister AdblockHelper engine client 183 public void waitForReady()
291 * @return `true` if the last instance is destroyed 184 {
292 */ 185 if (engineCreated == null)
186 {
187 throw new IllegalStateException("Usage exception: call retain(true) first" );
188 }
189
190 try
191 {
192 Log.d(TAG, "Waiting for ready ...");
193 engineCreated.await();
194 Log.d(TAG, "Ready");
195 }
196 catch (InterruptedException e)
197 {
198 Log.w(TAG, "Interrupted", e);
199 }
200 }
201
202 @Override
203 public AdblockEngine getEngine()
204 {
205 return engine;
206 }
207
208 @Override
293 public synchronized boolean release() 209 public synchronized boolean release()
294 { 210 {
295 boolean lastInstance = false; 211 boolean lastInstance = false;
296 212
297 if (referenceCounter.decrementAndGet() == 0) 213 if (referenceCounter.decrementAndGet() == 0)
298 { 214 {
299 lastInstance = true; 215 lastInstance = true;
300 216
301 if (engineCreated != null) 217 if (engineCreated != null)
302 { 218 {
303 // retained asynchronously 219 // retained asynchronously
304 waitForReady(); 220 waitForReady();
305 disposeAdblock(); 221 disposeAdblock();
306 222
307 // to unlock waiting client in waitForReady() 223 // to unlock waiting client in waitForReady()
308 engineCreated.countDown(); 224 engineCreated.countDown();
309 engineCreated = null; 225 engineCreated = null;
310 } 226 }
311 else 227 else
312 { 228 {
313 disposeAdblock(); 229 disposeAdblock();
314 } 230 }
315 } 231 }
316 return lastInstance; 232 return lastInstance;
317 } 233 }
234
235 private void disposeAdblock()
236 {
237 Log.w(TAG, "Disposing adblock engine");
238
239 engine.dispose();
240 engine = null;
241
242 // sometimes we need to deinit something after AdblockEngine instance dispos ed
243 // eg. release user settings
244 if (engineDisposedCallback != null)
245 {
246 engineDisposedCallback.run();
247 }
248 }
249
250 @Override
251 public int getCounter()
252 {
253 return referenceCounter.get();
254 }
318 } 255 }
OLDNEW

Powered by Google App Engine
This is Rietveld